OHLC.dev editorial

MarketFlow IPO & Smart Money Trading Intelligence

MarketFlow analyzes IPO events and smart money investor activity to identify potential opportunities, rank investor activity, and generate a structured trading research watchlist.

October 14, 202616 min readRafatar
MarketFlow IPO & Smart Money Trading Intelligence

Initial Public Offering (IPO) and institutional investor activity can provide useful information for equity market research. IPO data can reveal newly listed securities, indicative pricing, offering values, exchanges, sectors, and instrument characteristics, while investor transaction data can show documented changes in an investor's position. Combining these two information sources can provide a more structured framework for identifying IPO opportunities and examining whether an IPO security overlaps with documented investor activity.

This project develops a MarketFlow IPO & Smart Money Trading Intelligence System using the MarketFlow API. The system retrieves IPO events and investor trade activity, converts the API responses into structured DataFrames, validates and normalizes the data, calculates investor position changes, ranks smart-money activity, classifies IPO candidates, and produces a visual trading research dashboard.

The analysis is configured around the investor slug warren-buffett, with buy transactions and a maximum of 100 trade records. IPO events are analyzed from November 2, 2025 to November 9, 2025, while investor trade activity is analyzed from April 1, 2025 to July 1, 2025. marketflow_ipo_smartmoney_trader

The system does not interpret investor activity as an automatic BUY signal. Instead, it produces classifications such as PRIORITY REVIEW, WATCHLIST, LOW PRIORITY, REVIEW OVERLAP, IPO WATCHLIST, and INSUFFICIENT DATA. These classifications are intended to support further research rather than replace fundamental or market-based analysis.


Cell 1 — MarketFlow API Configuration

The first cell prepares the Python environment and establishes the MarketFlow API connection. It imports Requests for API communication, Pandas and NumPy for data processing, Matplotlib for visualization, and the IPython display function for presenting tabular results.

The code also defines the IPO period, investor identity, transaction type, trade limit, transaction period, request timeout, and output directory. The API key is retrieved from the RAPIDAPI_KEY environment variable or entered interactively through getpass, preventing the credential from being directly exposed in the article. marketflow_ipo_smartmoney_trader

Code

# ============================================================
# CELL 1 — MARKETFLOW API CONFIGURATION
# IPO & SMART MONEY TRADING INTELLIGENCE
# ============================================================

import sys
import subprocess
import os
import requests
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings

from datetime import datetime, timedelta
from IPython.display import display

warnings.filterwarnings("ignore")

# ------------------------------------------------------------
# INSTALL DEPENDENCIES
# ------------------------------------------------------------

packages = [
    "requests",
    "pandas",
    "numpy",
    "matplotlib"
]

for package in packages:

    try:
        __import__(package)

    except ImportError:

        subprocess.check_call([
            sys.executable,
            "-m",
            "pip",
            "install",
            "-q",
            package
        ])

# ------------------------------------------------------------
# API CONFIGURATION
# ------------------------------------------------------------

API_KEY = os.getenv(
    "RAPIDAPI_KEY",
    ""
).strip()

if not API_KEY:

    from getpass import getpass

    API_KEY = getpass(
        "Enter your RapidAPI Key: "
    ).strip()

BASE_URL = (
    "https://marketflow-all-in-one-market-finance-api"
    ".p.rapidapi.com"
)

HEADERS = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": (
        "marketflow-all-in-one-market-finance-api"
        ".p.rapidapi.com"
    )
}

# ------------------------------------------------------------
# IPO SETTINGS
# ------------------------------------------------------------

IPO_START_DATE = "2025-11-02"
IPO_END_DATE = "2025-11-09"
IPO_SKIP = 0

# ------------------------------------------------------------
# SMART MONEY SETTINGS
# ------------------------------------------------------------

INVESTOR_SLUG = "warren-buffett"

TRADE_TYPE = "buy"

TRADE_LIMIT = 100

TRADE_SKIP = 0

TRADE_START_DATE = "2025-04-01"

TRADE_END_DATE = "2025-07-01"

# ------------------------------------------------------------
# SYSTEM SETTINGS
# ------------------------------------------------------------

REQUEST_TIMEOUT = 30

OUTPUT_DIR = "marketflow_trading_results"

os.makedirs(
    OUTPUT_DIR,
    exist_ok=True
)

# ------------------------------------------------------------
# API REQUEST FUNCTION
# ------------------------------------------------------------

def marketflow_get(
    endpoint,
    params=None
):

    url = (
        f"{BASE_URL}/"
        f"{endpoint.lstrip('/')}"
    )

    try:

        response = requests.get(
            url,
            headers=HEADERS,
            params=params,
            timeout=REQUEST_TIMEOUT
        )

        response.raise_for_status()

        return response.json()

    except requests.exceptions.HTTPError as error:

        print(
            f"HTTP ERROR [{endpoint}]: "
            f"{error}"
        )

        return None

    except requests.exceptions.RequestException as error:

        print(
            f"CONNECTION ERROR [{endpoint}]: "
            f"{error}"
        )

        return None

    except ValueError:

        print(
            f"INVALID JSON RESPONSE "
            f"[{endpoint}]"
        )

        return None


# ------------------------------------------------------------
# CONFIGURATION SUMMARY
# ------------------------------------------------------------

print("=" * 65)

print(
    "MARKETFLOW — IPO & SMART MONEY "
    "TRADING INTELLIGENCE"
)

print("=" * 65)

print(
    f"Investor       : "
    f"{INVESTOR_SLUG}"
)

print(
    f"Trade Type     : "
    f"{TRADE_TYPE.upper()}"
)

print(
    f"IPO Period     : "
    f"{IPO_START_DATE} to {IPO_END_DATE}"
)

print(
    f"Trading Period : "
    f"{TRADE_START_DATE} to {TRADE_END_DATE}"
)

print(
    f"API Key        : "
    f"{'CONFIGURED' if API_KEY else 'MISSING'}"
)

print(
    f"Output Folder  : "
    f"{OUTPUT_DIR}"
)

print("=" * 65)

Cell 1 therefore functions as the control layer for the entire analysis. The marketflow_get() function is reusable, so the same API communication structure can be applied to both IPO and investor activity endpoints. marketflow_ipo_smartmoney_trader


Cell 2 — API Data Extraction & Validation

The second cell retrieves the two primary datasets.

The first request uses the ipos-events endpoint to obtain IPO information within the selected period. The second uses the trade-activity endpoint to retrieve documented purchases associated with the configured investor slug. marketflow_ipo_smartmoney_trader

Because API responses can use different JSON structures, the extract_records() function searches common containers such as data, results, items, events, trades, ipos, and records. The resulting records are converted into Pandas DataFrames using pd.json_normalize(). marketflow_ipo_smartmoney_trader

Code

# ============================================================
# CELL 2 — API DATA EXTRACTION & VALIDATION
# ============================================================

def extract_records(payload):

    """
    Extract list of records from
    common API JSON structures.
    """

    if isinstance(payload, list):

        return payload

    if isinstance(payload, dict):

        for key in [
            "data",
            "results",
            "items",
            "events",
            "trades",
            "ipos",
            "records"
        ]:

            value = payload.get(key)

            if isinstance(value, list):

                return value

            if isinstance(value, dict):

                records = extract_records(
                    value
                )

                if records:

                    return records

    return []


# ------------------------------------------------------------
# FETCH IPO EVENTS
# ------------------------------------------------------------

ipo_params = {

    "skip":
        IPO_SKIP,

    "start_date":
        IPO_START_DATE,

    "end_date":
        IPO_END_DATE
}

ipo_response = marketflow_get(
    "ipos-events",
    ipo_params
)

# ------------------------------------------------------------
# FETCH INVESTOR TRADE ACTIVITY
# ------------------------------------------------------------

trade_params = {

    "skip":
        TRADE_SKIP,

    "trade_type":
        TRADE_TYPE,

    "limit":
        TRADE_LIMIT,

    "slug":
        INVESTOR_SLUG,

    "time_range":
        f"{TRADE_START_DATE}:{TRADE_END_DATE}"
}

trade_response = marketflow_get(
    "trade-activity",
    trade_params
)

# ------------------------------------------------------------
# EXTRACT RECORDS
# ------------------------------------------------------------

ipo_records = extract_records(
    ipo_response
)

trade_records = extract_records(
    trade_response
)

df_ipo_raw = pd.json_normalize(
    ipo_records
)

df_trade_raw = pd.json_normalize(
    trade_records
)

# ------------------------------------------------------------
# STATUS
# ------------------------------------------------------------

print("=" * 65)

print(
    "MARKETFLOW — API DATA EXTRACTION"
)

print("=" * 65)

print(
    "IPO API Status   :",
    "OK"
    if ipo_response is not None
    else "FAILED"
)

print(
    "Trade API Status :",
    "OK"
    if trade_response is not None
    else "FAILED"
)

print(
    "IPO Records      :",
    len(df_ipo_raw)
)

print(
    "Trade Records    :",
    len(df_trade_raw)
)

print("\nIPO DATA PREVIEW")

display(
    df_ipo_raw.head(10)
)

print(
    "\nINVESTOR TRADE DATA PREVIEW"
)

display(
    df_trade_raw.head(10)
)

print(
    "\nIPO COLUMNS:"
)

print(
    df_ipo_raw.columns.tolist()
)

print(
    "\nTRADE COLUMNS:"
)

print(
    df_trade_raw.columns.tolist()
)

Output dari Cell 2 menjadi dasar untuk menentukan apakah API berhasil memberikan data dan apakah struktur respons sesuai dengan kebutuhan analisis.


Cell 3 — Verified Data Cleaning & Feature Engineering

Cell 3 mengubah raw API data menjadi variabel analitis.

Untuk IPO, sistem mengambil ticker, company name, IPO date, sector, country, exchange, currency, status, availability, price range, number of shares, dan reported offer value.

Jika exact_price tidak tersedia, sistem menggunakan midpoint dari price_from dan price_to sebagai indicative price. Nilai ini hanya merupakan estimasi dan bukan harga penawaran yang dikonfirmasi. marketflow_ipo_smartmoney_trader

Sistem juga mengidentifikasi jenis instrumen berdasarkan nama perusahaan, yaitu WARRANT, ETF, SPAC, UNIT, atau EQUITY / REVIEW. marketflow_ipo_smartmoney_trader

Untuk investor activity, sistem menghitung:

\[ Shares\ Change = Shares_{after} - Shares_{before} \]

Kemudian:

\[ Position\ Change\ \% = \frac{Shares\ Change} {Shares_{before}} \times 100 \]

Sistem juga menghitung estimasi perubahan nilai posisi, portfolio weight, dan filing lag. marketflow_ipo_smartmoney_trader

Code

# ============================================================
# CELL 3 — VERIFIED DATA CLEANING & FEATURE ENGINEERING
# ============================================================

# ------------------------------------------------------------
# IPO NORMALIZATION
# ------------------------------------------------------------

df_ipo = pd.DataFrame()

df_ipo["ticker"] = (
    df_ipo_raw["ticker"]
    .astype("string")
    .str.upper()
)

df_ipo["company"] = (
    df_ipo_raw["name"]
)

df_ipo["ipo_date"] = pd.to_datetime(
    df_ipo_raw["date"],
    errors="coerce"
)

df_ipo["sector"] = (
    df_ipo_raw["sector"]
)

df_ipo["country"] = (
    df_ipo_raw["country_iso"]
)

df_ipo["exchange"] = (
    df_ipo_raw["exchange"]
)

df_ipo["currency"] = (
    df_ipo_raw["currency"]
)

df_ipo["status"] = (
    df_ipo_raw["status"]
)

df_ipo["is_available"] = (
    df_ipo_raw["is_available"]
)

# ------------------------------------------------------------
# NUMERIC IPO FIELDS
# ------------------------------------------------------------

for col in [

    "price_range.exact_price",

    "price_range.price_from",

    "price_range.price_to",

    "number_of_shares",

    "total_shares_value"

]:

    df_ipo_raw[col] = pd.to_numeric(
        df_ipo_raw[col],
        errors="coerce"
    )

# ------------------------------------------------------------
# PRICE NORMALIZATION
# ------------------------------------------------------------

exact = (
    df_ipo_raw[
        "price_range.exact_price"
    ]
    .replace(0, np.nan)
)

low = (
    df_ipo_raw[
        "price_range.price_from"
    ]
    .replace(0, np.nan)
)

high = (
    df_ipo_raw[
        "price_range.price_to"
    ]
    .replace(0, np.nan)
)

df_ipo["ipo_price"] = exact

df_ipo["price_low"] = low

df_ipo["price_high"] = high

# Midpoint is only an estimate
df_ipo["indicative_price"] = (
    exact.fillna(
        (low + high) / 2
    )
)

df_ipo["shares_offered"] = (
    df_ipo_raw[
        "number_of_shares"
    ]
    .replace(0, np.nan)
)

df_ipo["reported_offer_value"] = (
    df_ipo_raw[
        "total_shares_value"
    ]
    .replace(0, np.nan)
)

df_ipo["offer_value"] = (
    df_ipo["reported_offer_value"]
)

# ------------------------------------------------------------
# INSTRUMENT IDENTIFICATION
# ------------------------------------------------------------

name = (
    df_ipo["company"]
    .fillna("")
    .str.lower()
)

df_ipo["instrument_type"] = np.select(

    [

        name.str.contains(
            r"\bwarrants?\b",
            regex=True
        ),

        name.str.contains(
            r"\betf\b|\bexchange traded fund\b",
            regex=True
        ),

        name.str.contains(
            r"\bspac\b|\bacquisition corp",
            regex=True
        ),

        name.str.contains(
            r"\bunits?\b",
            regex=True
        )

    ],

    [
        "WARRANT",
        "ETF",
        "SPAC",
        "UNIT"
    ],

    default="EQUITY / REVIEW"
)

# ------------------------------------------------------------
# TRADE NORMALIZATION
# ------------------------------------------------------------

df_trade = pd.DataFrame()

df_trade["ticker"] = (
    df_trade_raw["T"]
    .astype("string")
    .str.upper()
)

df_trade["company"] = (
    df_trade_raw["company"]
)

df_trade["cik"] = (
    df_trade_raw["cik"]
)

df_trade["trade_date"] = pd.to_datetime(
    df_trade_raw["trade_date"],
    errors="coerce"
)

df_trade["filing_date"] = pd.to_datetime(
    df_trade_raw["filing_date"],
    errors="coerce"
)

# ------------------------------------------------------------
# NUMERIC TRADE FIELDS
# ------------------------------------------------------------

for col in [

    "shares_before",

    "shares_after",

    "price",

    "value",

    "portfolio_value"

]:

    df_trade[col] = pd.to_numeric(
        df_trade_raw[col],
        errors="coerce"
    )

df_trade["form"] = (
    df_trade_raw["form"]
)

df_trade["outdated"] = (
    df_trade_raw["outdated"]
)

# ------------------------------------------------------------
# POSITION CHANGE
# ------------------------------------------------------------

df_trade["shares_change"] = (

    df_trade["shares_after"]

    -

    df_trade["shares_before"]

)

df_trade["position_change_pct"] = np.where(

    df_trade["shares_before"] > 0,

    (
        df_trade["shares_change"]
        /
        df_trade["shares_before"]
        *
        100
    ),

    np.nan
)

df_trade["position_action"] = np.select(

    [

        df_trade["shares_change"] > 0,

        df_trade["shares_change"] < 0,

        df_trade["shares_change"] == 0

    ],

    [

        "INCREASED",

        "DECREASED",

        "UNCHANGED"

    ],

    default="UNKNOWN"
)

df_trade[
    "position_value_change_est"
] = (

    df_trade["shares_change"]
    *
    df_trade["price"]

)

df_trade[
    "portfolio_weight_pct"
] = np.where(

    df_trade["portfolio_value"] > 0,

    (
        df_trade["value"]
        /
        df_trade["portfolio_value"]
        *
        100
    ),

    np.nan
)

df_trade[
    "filing_lag_days"
] = (

    df_trade["filing_date"]
    -
    df_trade["trade_date"]

).dt.days

# ------------------------------------------------------------
# VALIDATION
# ------------------------------------------------------------

valid_ipo = (
    df_ipo
    .dropna(
        subset=["ticker"]
    )
    .copy()
)

valid_trade = df_trade[

    df_trade["ticker"].notna()

    &

    (
        df_trade["shares_change"] > 0
    )

].copy()

print("=" * 70)

print(
    "MARKETFLOW — VERIFIED DATA PROCESSING"
)

print("=" * 70)

print(
    f"IPO Records              : "
    f"{len(valid_ipo)}"
)

print(
    f"Investor Records         : "
    f"{len(df_trade)}"
)

print(
    f"Increased Positions      : "
    f"{len(valid_trade)}"
)

print(
    f"IPO With Indicative Price: "
    f"{valid_ipo['indicative_price'].notna().sum()}"
)

print(
    f"IPO With Reported Value  : "
    f"{valid_ipo['offer_value'].notna().sum()}"
)

print(
    "\nINVESTOR POSITION CHANGES"
)

display(
    valid_trade[
        [
            "ticker",
            "company",
            "shares_before",
            "shares_after",
            "shares_change",
            "position_change_pct",
            "value",
            "portfolio_weight_pct",
            "filing_lag_days"
        ]
    ]
)

print(
    "\nIPO DATA"
)

display(
    valid_ipo[
        [
            "ticker",
            "company",
            "instrument_type",
            "ipo_date",
            "indicative_price",
            "currency",
            "offer_value",
            "status"
        ]
    ].head(20)
)

Data cleaning pada tahap ini sangat penting karena sistem hanya memasukkan position increase ke dalam valid_trade. Artinya, ranking smart-money pada tahap berikutnya berfokus pada transaksi yang menunjukkan peningkatan jumlah saham. marketflow_ipo_smartmoney_trader


Cell 4 — Smart Money Intelligence & IPO Screening

Cell 4 mengubah data yang sudah divalidasi menjadi intelligence score.

Untuk setiap ticker, aktivitas investor diagregasi berdasarkan:

  • jumlah transaksi,

  • total saham yang bertambah,

  • total reported transaction value,

  • estimated position increase,

  • portfolio weight,

  • position change percentage,

  • first trade,

  • last trade,

  • last filing.

Kemudian sistem menghitung ranking relatif berdasarkan estimated position increase dan portfolio weight.

Formula activity score adalah:

\[ Activity\ Score = 0.70(Value\ Rank) + 0.30(Weight\ Rank) \]

Kemudian klasifikasi dilakukan sebagai berikut:

Activity Score

Classification

≥ 80

PRIORITY REVIEW

≥ 60

WATCHLIST

< 60

LOW PRIORITY

marketflow_ipo_smartmoney_trader

IPO kemudian di-merge dengan smart-money dataset berdasarkan ticker. Jika terdapat investor overlap, IPO diklasifikasikan sebagai REVIEW OVERLAP. Jika tidak terdapat overlap tetapi data IPO cukup lengkap, statusnya menjadi IPO WATCHLIST. Jika data tidak mencukupi, sistem menghasilkan INSUFFICIENT DATA. marketflow_ipo_smartmoney_trader

Code

# ============================================================
# CELL 4 — SMART MONEY INTELLIGENCE & IPO SCREENING
# ============================================================

# ------------------------------------------------------------
# SMART MONEY RANKING
# ------------------------------------------------------------

smart_money = (

    valid_trade

    .groupby(
        "ticker",
        as_index=False
    )

    .agg(

        company=(
            "company",
            "first"
        ),

        trade_count=(
            "ticker",
            "size"
        ),

        total_shares=(
            "shares_change",
            "sum"
        ),

        total_value=(
            "value",
            "sum"
        ),

        estimated_position_increase=(
            "position_value_change_est",
            "sum"
        ),

        portfolio_weight_pct=(
            "portfolio_weight_pct",
            "max"
        ),

        position_change_pct=(
            "position_change_pct",
            "max"
        ),

        first_trade=(
            "trade_date",
            "min"
        ),

        last_trade=(
            "trade_date",
            "max"
        ),

        last_filing=(
            "filing_date",
            "max"
        )
    )
)

# ------------------------------------------------------------
# NUMERIC CONVERSION
# ------------------------------------------------------------

numeric_cols = [

    "trade_count",

    "total_shares",

    "total_value",

    "estimated_position_increase",

    "portfolio_weight_pct",

    "position_change_pct"

]

for col in numeric_cols:

    smart_money[col] = pd.to_numeric(
        smart_money[col],
        errors="coerce"
    )

# ------------------------------------------------------------
# RELATIVE RANKING
# ------------------------------------------------------------

if not smart_money.empty:

    smart_money[
        "value_rank_pct"
    ] = (

        smart_money[
            "estimated_position_increase"
        ]

        .rank(pct=True)

        * 100
    )

    smart_money[
        "weight_rank_pct"
    ] = (

        smart_money[
            "portfolio_weight_pct"
        ]

        .rank(pct=True)

        * 100
    )

    # --------------------------------------------------------
    # ACTIVITY SCORE
    # --------------------------------------------------------

    smart_money[
        "activity_score"
    ] = (

        0.70
        *
        smart_money[
            "value_rank_pct"
        ]

        +

        0.30
        *
        smart_money[
            "weight_rank_pct"
        ]

    )

    # --------------------------------------------------------
    # DECISION
    # --------------------------------------------------------

    smart_money[
        "decision"
    ] = np.select(

        [

            smart_money[
                "activity_score"
            ] >= 80,

            smart_money[
                "activity_score"
            ] >= 60

        ],

        [

            "PRIORITY REVIEW",

            "WATCHLIST"

        ],

        default="LOW PRIORITY"
    )

    smart_money[
        "activity_status"
    ] = smart_money[
        "decision"
    ]

    smart_money = smart_money.sort_values(
        "activity_score",
        ascending=False
    )

else:

    smart_money[
        "activity_score"
    ] = pd.Series(
        dtype=float
    )

    smart_money[
        "decision"
    ] = pd.Series(
        dtype=str
    )

    smart_money[
        "activity_status"
    ] = pd.Series(
        dtype=str
    )

# ------------------------------------------------------------
# IPO CLASSIFICATION
# ------------------------------------------------------------

ipo_analysis = (
    valid_ipo.copy()
)

ipo_analysis[
    "ipo_data_complete"
] = (

    ipo_analysis[
        "indicative_price"
    ].notna()

    &

    ipo_analysis[
        "ipo_date"
    ].notna()

)

# ------------------------------------------------------------
# MERGE SMART MONEY
# ------------------------------------------------------------

ipo_analysis = ipo_analysis.merge(

    smart_money[
        [
            "ticker",
            "trade_count",
            "total_value",
            "activity_score"
        ]
    ],

    on="ticker",

    how="left"
)

ipo_analysis[
    "investor_overlap"
] = (

    ipo_analysis[
        "trade_count"
    ].notna()

)

# ------------------------------------------------------------
# FINAL IPO DECISION
# ------------------------------------------------------------

ipo_analysis[
    "decision"
] = np.select(

    [

        ipo_analysis[
            "investor_overlap"
        ],

        ipo_analysis[
            "ipo_data_complete"
        ]

    ],

    [

        "REVIEW OVERLAP",

        "IPO WATCHLIST"

    ],

    default="INSUFFICIENT DATA"
)

# ------------------------------------------------------------
# SMART MONEY SUMMARY
# ------------------------------------------------------------

print("=" * 70)

print(
    "SMART MONEY — "
    "POSITION INCREASE RANKING"
)

print("=" * 70)

display(
    smart_money[
        [
            "ticker",
            "company",
            "total_shares",
            "estimated_position_increase",
            "portfolio_weight_pct",
            "activity_score",
            "decision"
        ]
    ].head(20)
)

# ------------------------------------------------------------
# IPO SUMMARY
# ------------------------------------------------------------

print(
    "\n" + "=" * 70
)

print(
    "IPO OPPORTUNITY SCREENING"
)

print("=" * 70)

display(
    ipo_analysis[
        [
            "ticker",
            "company",
            "instrument_type",
            "ipo_date",
            "indicative_price",
            "offer_value",
            "decision"
        ]
    ].head(20)
)

print(
    "\nSUMMARY"
)

print(
    f"IPO Candidates   : "
    f"{len(ipo_analysis)}"
)

print(
    f"Investor Tickers : "
    f"{len(smart_money)}"
)

print(
    f"IPO Overlap      : "
    f"{ipo_analysis['investor_overlap'].sum()}"
)

Hasil Cell 4 harus dipahami sebagai research ranking, bukan prediksi return. Misalnya, PRIORITY REVIEW berarti aktivitas investor berada pada ranking tinggi berdasarkan formula yang digunakan. Status tersebut tidak membuktikan bahwa saham tersebut akan naik.


Cell 5 — Trading Dashboard & Export

Cell terakhir mengubah hasil analisis menjadi dashboard visual dan file output.

Dashboard terdiri dari empat komponen:

  1. Top Smart Money — Transaction Value

  2. Investor Trade Frequency

  3. Top IPO — Offer Value

  4. Trading Watchlist Distribution

Dashboard disimpan sebagai:

marketflow_trading_results/marketflow_trading_dashboard.png

Selain dashboard, sistem menghasilkan dua CSV:

marketflow_trading_results/smart_money_analysis.csv
marketflow_trading_results/ipo_opportunity_analysis.csv

Struktur output tersebut memang ditentukan dalam Cell 5 pada file sumber. marketflow_ipo_smartmoney_trader marketflow_ipo_smartmoney_trader

Code

# ============================================================
# CELL 5 — TRADING DASHBOARD & EXPORT
# ============================================================

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from matplotlib.ticker import FuncFormatter

os.makedirs(
    OUTPUT_DIR,
    exist_ok=True
)

# ------------------------------------------------------------
# DATA TYPE VALIDATION
# ------------------------------------------------------------

smart_money = (
    smart_money.copy()
)

ipo_analysis = (
    ipo_analysis.copy()
)

numeric_columns = [

    "total_value",

    "total_shares",

    "trade_count",

    "activity_score"

]

for col in numeric_columns:

    if col in smart_money.columns:

        smart_money[col] = pd.to_numeric(
            smart_money[col],
            errors="coerce"
        )

for col in [

    "ipo_price",

    "offer_value",

    "trade_count"

]:

    if col in ipo_analysis.columns:

        ipo_analysis[col] = pd.to_numeric(
            ipo_analysis[col],
            errors="coerce"
        )

print("=" * 70)

print(
    "MARKETFLOW — DATA VALIDATION"
)

print("=" * 70)

print(
    f"Smart Money Records : "
    f"{len(smart_money)}"
)

print(
    f"IPO Records         : "
    f"{len(ipo_analysis)}"
)

print(
    f"Smart Money Values  : "
    f"{smart_money['total_value'].notna().sum()}"
)

print(
    f"IPO Offer Values    : "
    f"{ipo_analysis['offer_value'].notna().sum()}"
)

# ------------------------------------------------------------
# CREATE DASHBOARD
# ------------------------------------------------------------

plt.style.use(
    "dark_background"
)

fig, axes = plt.subplots(
    2,
    2,
    figsize=(16, 11)
)

fig.patch.set_facecolor(
    "#0b1220"
)

for ax in axes.flat:

    ax.set_facecolor(
        "#172235"
    )

    ax.grid(
        alpha=0.15,
        axis="y"
    )


def empty_chart(
    ax,
    message
):

    ax.text(

        0.5,

        0.5,

        message,

        ha="center",

        va="center",

        fontsize=12,

        color="#94a3b8",

        transform=ax.transAxes
    )


# ------------------------------------------------------------
# CHART 1 — TOP SMART MONEY BY VALUE
# ------------------------------------------------------------

ax = axes[0, 0]

top_value = (

    smart_money

    .dropna(
        subset=["total_value"]
    )

    .nlargest(
        10,
        "total_value"
    )
)

if not top_value.empty:

    ax.barh(

        top_value[
            "ticker"
        ].astype(str).iloc[::-1],

        top_value[
            "total_value"
        ].iloc[::-1],

        color="#22c55e"
    )

    ax.xaxis.set_major_formatter(

        FuncFormatter(
            lambda x, _: f"{x:,.2g}"
        )
    )

else:

    empty_chart(
        ax,
        "NO VALID SMART MONEY VALUE DATA"
    )

ax.set_title(
    "TOP SMART MONEY — TRANSACTION VALUE",
    fontweight="bold"
)

ax.set_xlabel(
    "Reported Transaction Value"
)

# ------------------------------------------------------------
# CHART 2 — INVESTOR TRADE FREQUENCY
# ------------------------------------------------------------

ax = axes[0, 1]

top_frequency = (

    smart_money

    .dropna(
        subset=["trade_count"]
    )

    .nlargest(
        10,
        "trade_count"
    )
)

if not top_frequency.empty:

    ax.bar(

        top_frequency[
            "ticker"
        ].astype(str),

        top_frequency[
            "trade_count"
        ],

        color="#38bdf8"
    )

    ax.tick_params(
        axis="x",
        rotation=45
    )

else:

    empty_chart(
        ax,
        "NO VALID INVESTOR TRADE DATA"
    )

ax.set_title(
    "INVESTOR TRADE FREQUENCY",
    fontweight="bold"
)

ax.set_ylabel(
    "Trade Records"
)

# ------------------------------------------------------------
# CHART 3 — IPO OFFER VALUE
# ------------------------------------------------------------

ax = axes[1, 0]

top_ipo = (

    ipo_analysis

    .dropna(
        subset=["offer_value"]
    )

    .nlargest(
        10,
        "offer_value"
    )
)

if not top_ipo.empty:

    ax.barh(

        top_ipo[
            "ticker"
        ].astype(str).iloc[::-1],

        top_ipo[
            "offer_value"
        ].iloc[::-1],

        color="#f59e0b"
    )

else:

    empty_chart(
        ax,
        "IPO OFFER VALUE NOT AVAILABLE"
    )

ax.set_title(
    "TOP IPO — OFFER VALUE",
    fontweight="bold"
)

ax.set_xlabel(
    "Reported Offer Value"
)

# ------------------------------------------------------------
# CHART 4 — WATCHLIST DISTRIBUTION
# ------------------------------------------------------------

ax = axes[1, 1]

all_decisions = pd.concat(

    [

        smart_money[
            "decision"
        ],

        ipo_analysis[
            "decision"
        ]

    ],

    ignore_index=True

).dropna()

counts = (
    all_decisions.value_counts()
)

if not counts.empty:

    ax.bar(

        counts.index.astype(str),

        counts.values,

        color="#a78bfa"
    )

    ax.tick_params(
        axis="x",
        rotation=30
    )

else:

    empty_chart(
        ax,
        "NO WATCHLIST CLASSIFICATION"
    )

ax.set_title(
    "TRADING WATCHLIST DISTRIBUTION",
    fontweight="bold"
)

ax.set_ylabel(
    "Number of Candidates"
)

# ------------------------------------------------------------
# DASHBOARD TITLE
# ------------------------------------------------------------

fig.suptitle(

    "MARKETFLOW — IPO & SMART MONEY "
    "TRADING DASHBOARD",

    fontsize=17,

    fontweight="bold"
)

plt.tight_layout(
    rect=[
        0,
        0,
        1,
        0.95
    ]
)

# ------------------------------------------------------------
# EXPORT DASHBOARD
# ------------------------------------------------------------

dashboard_path = os.path.join(

    OUTPUT_DIR,

    "marketflow_trading_dashboard.png"
)

plt.savefig(

    dashboard_path,

    dpi=200,

    bbox_inches="tight"
)

plt.show()

# ------------------------------------------------------------
# EXPORT CSV
# ------------------------------------------------------------

smart_money_path = os.path.join(

    OUTPUT_DIR,

    "smart_money_analysis.csv"
)

ipo_path = os.path.join(

    OUTPUT_DIR,

    "ipo_opportunity_analysis.csv"
)

smart_money.to_csv(

    smart_money_path,

    index=False
)

ipo_analysis.to_csv(

    ipo_path,

    index=False
)

# ------------------------------------------------------------
# FINAL TRADING RESEARCH SUMMARY
# ------------------------------------------------------------

print(
    "\n" + "=" * 70
)

print(
    "MARKETFLOW — FINAL TRADING RESEARCH"
)

print("=" * 70)

print(
    f"IPO Candidates       : "
    f"{len(ipo_analysis)}"
)

print(
    f"Smart Money Tickers  : "
    f"{len(smart_money)}"
)

print(
    "\nTOP SMART MONEY CANDIDATES"
)

if smart_money.empty:

    print(
        "INSUFFICIENT DATA — "
        "Investor records need normalization."
    )

else:

    display(
        smart_money[
            [
                "ticker",
                "trade_count",
                "total_value",
                "activity_score",
                "decision"
            ]
        ].head(10)
    )

print(
    "\nIPO WATCHLIST"
)

if ipo_analysis.empty:

    print(
        "NO IPO DATA AVAILABLE"
    )

else:

    display(
        ipo_analysis[
            [
                "ticker",
                "company",
                "ipo_date",
                "ipo_price",
                "decision"
            ]
        ].head(15)
    )

print(
    "\n" + "=" * 70
)

print(
    "EXPORT COMPLETED"
)

print("=" * 70)

print(
    dashboard_path
)

print(
    smart_money_path
)

print(
    ipo_path
)

print(
    "\nNOTE: Watchlist results are "
    "not confirmed BUY/SELL signals."
)

Dashboard tersebut memberikan empat sudut pandang berbeda. Chart pertama mengurutkan smart-money berdasarkan transaction value, chart kedua berdasarkan frekuensi transaksi, chart ketiga berdasarkan IPO offer value, dan chart keempat menunjukkan distribusi klasifikasi hasil screening. marketflow_ipo_smartmoney_trader
Result:

result

Conclusion

The MarketFlow IPO & Smart Money Trading Intelligence System provides a structured framework for combining IPO information with documented investor position increases. The system begins by retrieving IPO events and investor transactions from MarketFlow, normalizes the raw API responses, validates the available records, and generates analytical features such as indicative IPO price, shares offered, position change, estimated position increase, portfolio weight, and filing lag.

The smart-money component ranks documented position increases using a relative activity score based primarily on estimated position increase and secondarily on portfolio weight. The resulting classifications identify securities requiring priority review, watchlist monitoring, or lower-priority analysis. The IPO component separately identifies IPO candidates and checks whether their tickers overlap with the investor activity dataset. marketflow_ipo_smartmoney_trader

The dashboard then consolidates the analysis into transaction-value rankings, investor trade frequency, IPO offer-value rankings, and watchlist distribution. The results are also exported into CSV files for further quantitative analysis. marketflow_ipo_smartmoney_trader

The output should not be interpreted as a direct BUY or SELL signal. A high smart-money activity score only indicates relatively high documented activity within the analyzed dataset. Likewise, REVIEW OVERLAP indicates that an IPO ticker appears in the investor activity dataset, but it does not establish that the investor participated in the IPO itself or that the security represents a favorable investment opportunity.

A particularly important limitation is that the source preserves reported transaction values and reported IPO offer values without assuming their precise economic definitions. The source code explicitly treats the IPO midpoint as an indicative estimate rather than a confirmed offer price. marketflow_ipo_smartmoney_trader

Therefore, this system is best used as a research and screening layer. Further analysis should incorporate company fundamentals, valuation, IPO prospectus information, market liquidity, price behavior after listing, investor filing context, and broader market conditions before any investment decision is made.