OHLC.dev editorialMARKET

Warren Buffett Investment Analysis Using MarketFlow API

This project analyzes Warren Buffett investment activity using MarketFlow API, including reported buy transactions, portfolio holdings, transaction value, and portfolio concentration.

October 10, 20269 min readRafatar
Warren Buffett Investment Analysis Using MarketFlow API

Institutional investment activity can provide useful information for understanding how large investment portfolios are positioned across different companies. By examining reported transactions and portfolio holdings, analysts can identify the largest reported purchases, major portfolio positions, portfolio concentration, and the distribution of reported capital across holdings.

This project develops a Warren Buffett Investment Intelligence System using the MarketFlow API. The system retrieves Warren Buffett-related trade activity and portfolio information, processes the returned records, calculates transaction and portfolio metrics, identifies the largest reported positions, and produces an investment analytics dashboard. The configured analysis uses buy transactions from April 1, 2025 to July 1, 2025, together with a portfolio snapshot dated June 30, 2024. warren_buffett_investment_intel…

The project is organized into five cells. Cell 1 establishes the API configuration, Cell 2 retrieves and inspects the trade and portfolio responses, Cell 3 standardizes the datasets, Cell 4 performs transaction and portfolio analysis, and Cell 5 generates the executive investment report and exports the results to Excel. warren_buffett_investment_intel… warren_buffett_investment_intel…

An important methodological point is that the two datasets use different dates. The trade activity represents a defined transaction period, while the portfolio data represent a separate portfolio snapshot. Therefore, the results should be interpreted as reported transaction and portfolio information rather than as a synchronized real-time portfolio flow.


Cell 1 — API Configuration and Analysis Parameters

The first cell prepares the Python environment and establishes the MarketFlow API connection. Requests is used for API communication, Pandas for data processing, NumPy for numerical calculations, Matplotlib for visualization, and IPython Display for presenting DataFrames.

The configuration defines Warren Buffett as the selected investor through the warren-buffett slug. The analysis is restricted to buy transactions during the specified trade period, while the portfolio snapshot uses the specified report date. warren_buffett_investment_intel…


# CELL 1 — CONFIGURATION
import os
import json
import requests
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from getpass import getpass
from IPython.display import display

HOST = "marketflow-all-in-one-market-finance-api.p.rapidapi.com"
BASE_URL = f"https://{HOST}"

API_KEY = os.getenv("RAPIDAPI_KEY", "").strip()
if not API_KEY:
    API_KEY = getpass("Masukkan RapidAPI Key: ").strip()

if not API_KEY:
    raise ValueError("RapidAPI Key wajib diisi.")

HEADERS = {
    "x-rapidapi-host": HOST,
    "x-rapidapi-key": API_KEY
}

SLUG = "warren-buffett"
TRADE_TYPE = "buy"
TIME_RANGE = "2025-04-01:2025-07-01"
REPORT_DATE = "2024-06-30"
LIMIT = 100
SKIP = 0

session = requests.Session()
session.headers.update(HEADERS)

def fetch_api(endpoint, params):
    try:
        response = session.get(
            f"{BASE_URL}/{endpoint}",
            params=params,
            timeout=40
        )
        print(f"{endpoint}: HTTP {response.status_code}")

        response.raise_for_status()
        return response.json()

    except requests.exceptions.RequestException as exc:
        print(f"API ERROR [{endpoint}]: {exc}")
        return None

    except ValueError:
        print(f"JSON ERROR [{endpoint}]: Response bukan JSON valid.")
        return None

print("=" * 65)
print("WARREN BUFFETT — TRADE & PORTFOLIO ANALYTICS")
print("=" * 65)
print("Investor      :", SLUG)
print("Trade Type    :", TRADE_TYPE)
print("Trade Period  :", TIME_RANGE)
print("Report Date   :", REPORT_DATE)
print("Configuration : READY")

The reusable fetch_api() function centralizes API communication and error handling. This makes the remaining cells easier to maintain because they can request different endpoints without repeating the HTTP configuration.

The API key is also requested securely through getpass() when the environment variable is unavailable. This is preferable to publishing a real API credential directly in a notebook.


Cell 2 — Trade Activity and Portfolio Data Extraction

The second cell constructs two API requests. The first retrieves trade activity, while the second retrieves portfolio checks. The trade request uses the configured trade type, limit, investor slug, and time range. The portfolio request uses English language output, the report date, and the investor slug. warren_buffett_investment_intel…

The cell also includes an inspection function that displays the response type, top-level keys or record count, and a JSON sample. This is useful because API responses should be inspected before designing the normalization process.


# CELL 2 — API DATA EXTRACTION

trade_params = {
    "skip": SKIP,
    "trade_type": TRADE_TYPE,
    "limit": LIMIT,
    "slug": SLUG,
    "time_range": TIME_RANGE
}

portfolio_params = {
    "lang": "en",
    "report_date": REPORT_DATE,
    "slug": SLUG
}

trade_raw = fetch_api("trade-activity", trade_params)
portfolio_raw = fetch_api("portofolio-checks", portfolio_params)

def inspect_response(name, data):
    print("\n" + "=" * 65)
    print(name)
    print("=" * 65)

    if data is None:
        print("STATUS: REQUEST FAILED")
        return

    print("Response Type:", type(data).__name__)

    if isinstance(data, dict):
        print("Top-Level Keys:", list(data.keys()))

    elif isinstance(data, list):
        print("Top-Level Records:", len(data))

    print("\nJSON SAMPLE:")
    print(json.dumps(
        data,
        indent=2,
        ensure_ascii=False,
        default=str
    )[:3500])

inspect_response("TRADE ACTIVITY", trade_raw)
inspect_response("PORTFOLIO CHECKS", portfolio_raw)

The inspection stage is important because the subsequent DataFrame construction depends on the actual response structure. The original project deliberately inspects the JSON before further processing. warren_buffett_investment_intel…


Cell 3 — Data Cleaning and Standardization

The third cell standardizes the trade and portfolio datasets. The function prepare_data() creates a standardized ticker field from T, copies the company name, converts relevant variables to numeric format, standardizes date fields, calculates net_shares for trade data, and converts portfolio_ratio into percentage form for portfolio data. warren_buffett_investment_intel…

Technical correction for copy-paste execution: the uploaded source calls prepare_data(trade_df, ...) and prepare_data(portfolio_df, ...), but those two DataFrames are not created in Cell 2. The version below adds the required raw-response-to-DataFrame conversion before running the original standardization logic. This does not change the analytical methodology.


# CELL 3 — DATA CLEANING & STANDARDIZATION

import pandas as pd
import numpy as np

def prepare_data(df, dataset):
    data = df.copy()

    # Standar identitas saham
    if "T" in data.columns:
        data["ticker"] = data["T"].astype(str).str.replace(
            ".US", "", regex=False
        )

    if "company" in data.columns:
        data["company_name"] = data["company"]

    # Konversi kolom numerik
    numeric_cols = [
        "value", "price", "shares",
        "shares_before", "shares_after",
        "portfolio_ratio", "change_in_shares",
        "change_in_value"
    ]

    for col in numeric_cols:
        if col in data.columns:
            data[col] = pd.to_numeric(data[col], errors="coerce")

    # Tanggal tanpa timezone
    for col in ["trade_date", "report_date", "filing_date"]:
        if col in data.columns:
            data[col] = pd.to_datetime(
                data[col], errors="coerce", utc=True
            ).dt.tz_localize(None)

    if dataset == "trade":
        if {"shares_before", "shares_after"}.issubset(data.columns):
            data["net_shares"] = (
                data["shares_after"] - data["shares_before"]
            )

    if dataset == "portfolio":
        if "portfolio_ratio" in data.columns:
            data["weight_pct"] = data["portfolio_ratio"] * 100

    return data


trade_clean = prepare_data(trade_df, "trade")
portfolio_clean = prepare_data(portfolio_df, "portfolio")

print("TRADE DATA:", len(trade_clean), "records")
display(trade_clean.head(10))

print("\nPORTFOLIO DATA:", len(portfolio_clean), "records")
display(portfolio_clean.head(10))

The most important derived variable in the trade dataset is:

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

A positive value indicates an increase in the reported share position, while a negative value indicates a reduction.

For portfolio data, the original project converts the portfolio ratio into a percentage:

\[ Weight(\%) = Portfolio\ Ratio \times 100 \]

This creates a directly interpretable portfolio-weight variable. warren_buffett_investment_intel…


Cell 4 — Investment Analytics Dashboard

The fourth cell aggregates the standardized datasets into two analytical tables.

The trade summary groups transactions by ticker and company and calculates total net shares, total reported trade value, and the number of transactions.

The portfolio summary groups portfolio holdings by ticker and company and calculates market value, shares, and portfolio weight. The project then calculates total reported portfolio value together with top-five and top-ten portfolio concentration. warren_buffett_investment_intel…


# CELL 4 — INVESTMENT ANALYTICS DASHBOARD

import matplotlib.pyplot as plt
from IPython.display import display

print("=" * 65)
print("WARREN BUFFETT | INVESTMENT ANALYTICS")
print("=" * 65)

# TRADE SUMMARY
trade_summary = (
    trade_clean.groupby(["ticker", "company_name"], as_index=False)
    .agg(
        net_shares=("net_shares", "sum"),
        trade_value=("value", "sum"),
        transactions=("ticker", "size")
    )
    .sort_values("trade_value", ascending=False)
)

# PORTFOLIO SUMMARY
portfolio_summary = (
    portfolio_clean.groupby(["ticker", "company_name"], as_index=False)
    .agg(
        market_value=("value", "sum"),
        shares=("shares", "sum"),
        weight_pct=("weight_pct", "sum")
    )
    .sort_values("market_value", ascending=False)
)

total_portfolio = portfolio_summary["market_value"].sum()

# KPI
print(f"\nTrade Records       : {len(trade_clean):,}")
print(f"Portfolio Holdings  : {len(portfolio_summary):,}")
print(f"Reported Holdings   : ${total_portfolio/1e9:,.2f} Billion")
print(f"Top 5 Concentration : {portfolio_summary['weight_pct'].head(5).sum():.2f}%")
print(f"Top 10 Concentration: {portfolio_summary['weight_pct'].head(10).sum():.2f}%")

print("\nTOP TRANSACTIONS")
display(trade_summary.head(10).style.format({
    "net_shares": "{:,.0f}",
    "trade_value": "${:,.2f}",
    "transactions": "{:,.0f}"
}))

print("\nTOP PORTFOLIO HOLDINGS")
display(portfolio_summary.head(15).style.format({
    "market_value": "${:,.0f}",
    "shares": "{:,.0f}",
    "weight_pct": "{:.2f}%"
}))

# Grafik 1
top_trade = trade_summary.head(10).sort_values("trade_value")

plt.figure(figsize=(11, 5))
plt.barh(top_trade["ticker"], top_trade["trade_value"]/1e6)
plt.xlabel("Transaction Value (USD Million)")
plt.title("Top Reported Buy Transactions")
plt.grid(axis="x", alpha=0.2)
plt.tight_layout()
plt.show()

# Grafik 2
top_holdings = portfolio_summary.head(10).sort_values("weight_pct")

plt.figure(figsize=(11, 5))
plt.barh(top_holdings["ticker"], top_holdings["weight_pct"])
plt.xlabel("Portfolio Weight (%)")
plt.title("Top 10 Portfolio Holdings")
plt.grid(axis="x", alpha=0.2)
plt.tight_layout()
plt.show()

The first chart ranks the largest reported buy transactions according to transaction value. The second chart ranks the largest portfolio holdings according to portfolio weight. These two perspectives should be interpreted differently: transaction value describes reported activity within the selected trade period, while portfolio weight describes the composition of the selected portfolio snapshot.

The original project uses these metrics to calculate the concentration of the top five and top ten holdings. warren_buffett_investment_intel…


Cell 5 — Executive Investment Report and Excel Export

The fifth cell produces the executive-level output. It calculates top-five and top-ten portfolio concentration and an HHI concentration index based on the market value of portfolio positions.

The HHI is calculated as:

\[ HHI = \sum_{i=1}^{n} \left( \frac{MarketValue_i} {TotalPortfolioValue} \right)^2 \]

A higher HHI indicates that a larger proportion of the reported portfolio value is concentrated in fewer holdings.

The project also records important methodological limitations, including the difference between the trade period and portfolio date and the fact that the trade dataset is restricted to buy transactions. warren_buffett_investment_intel…


# CELL 5 — EXECUTIVE REPORT & EXCEL EXPORT

import json
import pandas as pd
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.utils import get_column_letter

top5 = portfolio_summary["weight_pct"].head(5).sum()
top10 = portfolio_summary["weight_pct"].head(10).sum()

# HHI berdasarkan nilai posisi yang diperoleh
weights = portfolio_summary["market_value"] / total_portfolio
hhi = float((weights ** 2).sum())

report = [
    ["Trade Period", TIME_RANGE],
    ["Portfolio Date", REPORT_DATE],
    ["Trade Records", len(trade_clean)],
    ["Portfolio Holdings", len(portfolio_summary)],
    ["Reported Portfolio Value USD", total_portfolio],
    ["Top Buy Ticker", trade_summary.iloc[0]["ticker"]],
    ["Largest Holding", portfolio_summary.iloc[0]["ticker"]],
    ["Top 5 Concentration (%)", top5],
    ["Top 10 Concentration (%)", top10],
    ["HHI", hhi],
    ["Data Limitation", "Trade and portfolio dates differ"],
    ["Data Limitation", "Buy transactions only; net flow not established"]
]

report_df = pd.DataFrame(report, columns=["Metric", "Value"])

print("\nEXECUTIVE INVESTMENT SUMMARY")
display(report_df)

# Excel-safe conversion
def excel_safe(df):
    output = df.copy()

    for col in output.columns:
        if isinstance(output[col].dtype, pd.DatetimeTZDtype):
            output[col] = output[col].dt.tz_localize(None)

        elif output[col].dtype == "object":
            output[col] = output[col].map(
                lambda x: json.dumps(x, default=str)
                if isinstance(x, (dict, list, tuple))
                else x
            )

    return output

filename = "Warren_Buffett_Investment_Intelligence.xlsx"

sheets = {
    "Executive Summary": report_df,
    "Trade Analysis": trade_summary,
    "Portfolio Analysis": portfolio_summary,
    "Raw Trades": trade_clean,
    "Raw Portfolio": portfolio_clean
}

with pd.ExcelWriter(filename, engine="openpyxl") as writer:

    for sheet, df in sheets.items():
        excel_safe(df).to_excel(
            writer, sheet_name=sheet, index=False
        )

    workbook = writer.book

    for ws in workbook.worksheets:
        ws.freeze_panes = "A2"
        ws.auto_filter.ref = ws.dimensions

        for cell in ws[1]:
            cell.fill = PatternFill(
                "solid", fgColor="17365D"
            )
            cell.font = Font(
                color="FFFFFF", bold=True
            )
            cell.alignment = Alignment(
                horizontal="center"
            )

        for column in ws.columns:
            letter = get_column_letter(column[0].column)

            max_length = max(
                len(str(cell.value or ""))
                for cell in column
            )

            ws.column_dimensions[letter].width = min(
                max(max_length + 3, 14), 45
            )

print("\nEXCEL EXPORT SUCCESS:", filename)

try:
    from google.colab import files
    files.download(filename)
except ImportError:
    print("Saved in current working directory.")

The final Excel workbook contains five sheets:

  1. Executive Summary

  2. Trade Analysis

  3. Portfolio Analysis

  4. Raw Trades

  5. Raw Portfolio

This structure preserves both the processed analytical results and the underlying standardized datasets. The original code uses OpenPyXL formatting to freeze the first row, activate filters, format headers, and automatically adjust column widths. warren_buffett_investment_intel…

Conclusion

The Warren Buffett Investment Intelligence System provides a structured approach to analyzing reported investment activity and portfolio composition through the MarketFlow API. The workflow begins with API configuration and data retrieval, continues with data standardization and aggregation, and ends with transaction analysis, portfolio concentration analysis, visualization, and Excel reporting.

The trade analysis identifies the largest reported buy transactions based on aggregated transaction value, while the portfolio analysis identifies the largest reported holdings based on market value and portfolio weight. The system also calculates top-five concentration, top-ten concentration, and HHI to provide a quantitative view of portfolio concentration. warren_buffett_investment_intel… warren_buffett_investment_intel…

However, the results require careful interpretation. The configured trade dataset covers April 1, 2025 to July 1, 2025, whereas the portfolio snapshot is dated June 30, 2024. These dates are not synchronized. In addition, the transaction analysis is explicitly configured for buy transactions only, so the dataset does not establish complete net institutional flow. The original report therefore records both limitations directly. warren_buffett_investment_intel…

Consequently, this system should be interpreted as a reported investment activity and portfolio intelligence framework, not as a real-time representation of Warren Buffett's current portfolio or a direct trading signal. Its strongest analytical value comes from combining reported transaction activity, portfolio composition, concentration metrics, and structured visualization while keeping the limitations of the underlying data explicit.