Securities and Exchange Commission
US SEC 13F Whales
Introduction
The US SEC 13F Whales dataset by the US Securities and Exchange Commission (SEC) tracks the holdings of institutional investment managers with at least $100 million in assets under management. The data covers 18,877 US Equities, starts in May 2013, and is delivered on a daily frequency. This dataset is created by parsing Form 13F filings.
This dataset depends on the US Equity Security Master dataset because the US Equity Security Master dataset contains information on splits, dividends, and symbol changes.
For more information about the US SEC 13F Whales dataset, including CLI commands and pricing, see the dataset listing.
About the Provider
The mission of the U.S. Securities and Exchange Commission is to protect investors, maintain fair, orderly, and efficient markets, and facilitate capital formation. The SEC oversees the key participants in the securities world, including securities exchanges, securities brokers and dealers, investment advisors, and mutual funds. The SEC is concerned primarily with promoting the disclosure of important market-related information, maintaining fair dealing, and protecting against fraud.
Getting Started
The following snippet demonstrates how to request data from the SEC Whales dataset:
self._symbol = self.add_equity("AAPL", Resolution.DAILY).symbol
self._holdings_symbol = self.add_data(SEC13FHoldings, self._symbol).symbol _symbol = AddEquity("AAPL", Resolution.Daily).Symbol;
_holdingsSymbol = AddData<SEC13FHoldings>(_symbol).Symbol;
Requesting Data
To add SEC Whales data to your algorithm, call the AddDataadd_data method. Save a reference to the dataset Symbol so you can access the data later in your algorithm.
class SEC13FDataAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2020, 10, 1)
self.set_end_date(2020, 12, 31)
self.set_cash(100000)
self._symbol = self.add_equity("AAPL", Resolution.DAILY).symbol
self._dataset_symbol = self.add_data(SEC13FHoldings, self._symbol).symbol public class SEC13FDataAlgorithm : QCAlgorithm
{
private Symbol _symbol, _datasetSymbol;
public override void Initialize()
{
SetStartDate(2020, 10, 1);
SetEndDate(2020, 12, 31);
SetCash(100000);
_symbol = AddEquity("AAPL", Resolution.Daily).Symbol;
_datasetSymbol = AddData<SEC13FHoldings>(_symbol).Symbol;
}
}
Accessing Data
To get the current SEC Whales data, index the current Slice with the dataset Symbol. Slice objects deliver unique events to your algorithm as they happen, but the Slice may not contain data for your dataset at every time step. To avoid issues, check if the Slice contains the data you want before you index it.
def on_data(self, slice: Slice) -> None:
if slice.contains_key(self._dataset_symbol):
for holding in slice[self._dataset_symbol]:
self.log(f"{self._dataset_symbol} CIK {holding.manager_cik} at {slice.time}: {holding.amount} {holding.amount_type}") public override void OnData(Slice slice)
{
if (slice.ContainsKey(_datasetSymbol))
{
foreach (SEC13FHolding holding in slice[_datasetSymbol])
{
Log($"{_datasetSymbol} CIK {holding.ManagerCik} at {slice.Time}: {holding.Amount} {holding.AmountType}");
}
}
}
To iterate through all of the dataset objects in the current Slice, call the Getget method.
def on_data(self, slice: Slice) -> None:
for dataset_symbol, holdings in slice.get(SEC13FHoldings).items():
for holding in holdings:
self.log(f"{dataset_symbol} CIK {holding.manager_cik} at {slice.time}: {holding.amount} {holding.amount_type}") public override void OnData(Slice slice)
{
foreach (var kvp in slice.Get<SEC13FHoldings>())
{
var datasetSymbol = kvp.Key;
foreach (SEC13FHolding holding in kvp.Value)
{
Log($"{datasetSymbol} CIK {holding.ManagerCik} at {slice.Time}: {holding.Amount} {holding.AmountType}");
}
}
}
Historical Data
To get historical SEC Whales data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty.
# DataFrame history_df = self.history(SEC13FHoldings, self._dataset_symbol, timedelta(days=60), Resolution.DAILY, flatten=True) # Dataset objects history_bars = self.history[SEC13FHoldings](self._dataset_symbol, timedelta(days=60), Resolution.DAILY)
var history = History<SEC13FHoldings>(_datasetSymbol, TimeSpan.FromDays(60), Resolution.Daily);
For more information about historical data, see History Requests.
Remove Subscriptions
To remove your subscription to SEC Whales data, call the RemoveSecurityremove_security method.
self.remove_security(self._dataset_symbol)
RemoveSecurity(_datasetSymbol);
If you subscribe to SEC Whales data for assets in a dynamic universe, remove the dataset subscription when the asset leaves your universe. To view a common design pattern, see Track Security Changes.
Supported Managers
To follow a manager, filter the holdings by its CIK with the ManagerCikmanager_cik property. The following table shows the 50 largest managers by reported value in the second quarter of 2026:
| CIK | Manager |
|---|---|
| 2012383 | BlackRock Inc. |
| 2100119 | VANGUARD CAPITAL MANAGEMENT LLC |
| 93751 | STATE STREET CORP |
| 315066 | FMR LLC |
| 2100121 | VANGUARD PORTFOLIO MANAGEMENT LLC |
| 895421 | MORGAN STANLEY |
| 1214717 | GEODE CAPITAL MANAGEMENT LLC |
| 19617 | JPMORGAN CHASE & CO |
| 70858 | BANK OF AMERICA CORP /DE/ |
| 914208 | Invesco Ltd. |
| 1374170 | NORGES BANK |
| 80255 | PRICE T ROWE ASSOCIATES INC /MD/ |
| 886982 | GOLDMAN SACHS GROUP INC |
| 73124 | NORTHERN TRUST CORP |
| 1422849 | Capital World Investors |
| 884546 | CHARLES SCHWAB INVESTMENT MANAGEMENT INC |
| 1422848 | Capital Research Global Investors |
| 1610520 | UBS Group AG |
| 1390777 | Bank of New York Mellon Corp |
| 1000275 | ROYAL BANK OF CANADA |
| 902219 | WELLINGTON MANAGEMENT GROUP LLP |
| 72971 | WELLS FARGO & COMPANY/MN |
| 354204 | DIMENSIONAL FUND ADVISORS LP |
| 861177 | UBS AM a distinct business unit of UBS ASSET MANAGEMENT AMERICAS LLC |
| 820027 | AMERIPRISE FINANCIAL INC |
| 1562230 | Capital International Investors |
| 764068 | Legal & General Group Plc |
| 38777 | FRANKLIN RESOURCES INC |
| 933478 | VANGUARD FIDUCIARY TRUST CO |
| 1403438 | LPL Financial LLC |
| 1407543 | ENVESTNET ASSET MANAGEMENT INC |
| 1871926 | Nuveen LLC |
| 1330387 | Amundi |
| 720005 | RAYMOND JAMES FINANCIAL INC |
| 948046 | DEUTSCHE BANK AG |
| 850529 | Fisher Asset Management LLC |
| 312069 | BARCLAYS PLC |
| 912938 | MASSACHUSETTS FINANCIAL SERVICES CO /MA/ |
| 1109448 | ALLIANCEBERNSTEIN L.P. |
| 1067983 | Berkshire Hathaway Inc |
| 1167557 | AQR CAPITAL MANAGEMENT LLC |
| 927971 | BANK OF MONTREAL /CAN/ |
| 815917 | JONES FINANCIAL COMPANIES LLLP |
| 2146052 | Jupiter Topco LLC |
| 748054 | AMERICAN CENTURY COMPANIES INC |
| 1164508 | ARROWSTREET CAPITAL LIMITED PARTNERSHIP |
| 1811242 | Vanguard Global Advisers LLC |
| 831001 | CITIGROUP INC |
| 873630 | HSBC HOLDINGS PLC |
| 1126328 | PRINCIPAL FINANCIAL GROUP INC |
Example Applications
The US SEC 13F Whales dataset enables you to follow what large institutional investors hold and how their positions change. Examples include the following strategies:
- Following the quarterly positions of specific fund managers on the premise that they are more informed
- Buying the securities that institutions are accumulating and selling the ones they are reducing
- Avoiding crowded securities that many managers hold at the same time
Classic Algorithm Example
The following example algorithm buys AAPL when Parnassus Investments reports more shares of it than in the previous quarter. Otherwise, it liquidates the position.
from AlgorithmImports import *
class SEC13FDataAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2019, 1, 1)
self.set_end_date(2020, 8, 31)
self.set_cash(100000)
self.equity = self.add_equity("AAPL", Resolution.DAILY).symbol
self.add_data(SEC13FHoldings, self.equity)
self.shares_by_quarter = {}
def on_data(self, slice):
for _, point in slice.get(SEC13FHoldings).items():
for holding in point:
# Sum the share lines Parnassus Investments reports for each quarter.
if (holding.manager_cik != 948669 or holding.form_type != "13F-HR"
or holding.amount_type != "SH" or holding.put_call is not None):
continue
quarter = holding.period_end
self.shares_by_quarter[quarter] = self.shares_by_quarter.get(quarter, 0) + (holding.amount or 0)
self.log(f"{self.time:%Y-%m-%d} {holding.manager_name} reports {holding.amount:,.0f} shares "
f"for {quarter:%Y-%m-%d}")
quarters = [self.shares_by_quarter[q] for q in sorted(self.shares_by_quarter)]
if len(quarters) < 2 or slice.bars.count == 0:
return
# Buy when the manager adds shares, otherwise liquidate.
if quarters[-1] > quarters[-2]:
self.set_holdings(self.equity, 1)
else:
self.liquidate(self.equity) using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect;
using QuantConnect.Algorithm;
using QuantConnect.Data;
using QuantConnect.DataSource;
public class SEC13FDataAlgorithm : QCAlgorithm
{
private Symbol _equity;
private readonly Dictionary<DateTime, decimal> _sharesByQuarter = new();
public override void Initialize()
{
SetStartDate(2019, 1, 1);
SetEndDate(2020, 8, 31);
SetCash(100000);
_equity = AddEquity("AAPL", Resolution.Daily).Symbol;
AddData<SEC13FHoldings>(_equity);
}
public override void OnData(Slice slice)
{
foreach (var (_, point) in slice.Get<SEC13FHoldings>())
{
// Sum the share lines Parnassus Investments reports for each quarter.
foreach (var holding in point.OfType<SEC13FHolding>().Where(holding =>
holding.ManagerCik == 948669 && holding.FormType == "13F-HR" &&
holding.AmountType == "SH" && !holding.PutCall.HasValue))
{
_sharesByQuarter.TryGetValue(holding.PeriodEnd, out var reported);
_sharesByQuarter[holding.PeriodEnd] = reported + (holding.Amount ?? 0);
Log($"{Time:yyyy-MM-dd} {holding.ManagerName} reports {holding.Amount:N0} shares " +
$"for {holding.PeriodEnd:yyyy-MM-dd}");
}
}
var quarters = _sharesByQuarter.OrderBy(entry => entry.Key).Select(entry => entry.Value).ToList();
if (quarters.Count < 2 || slice.Bars.Count == 0)
{
return;
}
// Buy when the manager adds shares, otherwise liquidate.
if (quarters[^1] > quarters[^2])
{
SetHoldings(_equity, 1);
}
else
{
Liquidate(_equity);
}
}
}
Framework Algorithm Example
The following example algorithm compares how many managers report AAPL in two consecutive quarters once their 45-day filing deadline has passed. It emits an up insight when the later quarter has more managers and a down insight when it has fewer.
from AlgorithmImports import *
class SEC13FFrameworkAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 1, 1)
self.set_end_date(2020, 12, 31)
self.set_cash(100000)
self.universe_settings.resolution = Resolution.DAILY
self.set_universe_selection(ManualUniverseSelectionModel(
[Symbol.create("AAPL", SecurityType.EQUITY, Market.USA)]))
self.add_alpha(SEC13FCrowdingAlphaModel())
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
self.set_execution(ImmediateExecutionModel())
class SEC13FCrowdingAlphaModel(AlphaModel):
# Count a quarter only after its 45-day filing deadline has passed.
FILING_DEADLINE = timedelta(days=45)
def __init__(self):
self._holdings = {}
self._managers = {}
self._emitted = set()
def update(self, algorithm, data):
insights = []
for holdings_symbol, point in data.get(SEC13FHoldings).items():
equity = holdings_symbol.underlying
by_period = self._managers.setdefault(equity, {})
for holding in point:
if (holding.form_type != "13F-HR" or holding.amount_type != "SH"
or holding.put_call is not None
or algorithm.time > holding.period_end + self.FILING_DEADLINE):
continue
by_period.setdefault(holding.period_end, set()).add(holding.manager_cik)
closed = [p for p in sorted(by_period) if algorithm.time >= p + self.FILING_DEADLINE]
if len(closed) < 2 or (equity, closed[-1]) in self._emitted:
continue
self._emitted.add((equity, closed[-1]))
latest, previous = len(by_period[closed[-1]]), len(by_period[closed[-2]])
if latest == previous:
continue
algorithm.log(f"{algorithm.time:%Y-%m-%d} {equity.value}: {previous} -> {latest} managers")
direction = InsightDirection.UP if latest > previous else InsightDirection.DOWN
insights.append(Insight.price(equity, timedelta(days=30), direction))
return insights
def on_securities_changed(self, algorithm, changes):
for security in changes.added_securities:
self._holdings[security.symbol] = algorithm.add_data(SEC13FHoldings, security.symbol).symbol
for security in changes.removed_securities:
holdings_symbol = self._holdings.pop(security.symbol, None)
if holdings_symbol is not None:
algorithm.remove_security(holdings_symbol) using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect;
using QuantConnect.Algorithm;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.DataSource;
public class SEC13FFrameworkAlgorithm : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2020, 1, 1);
SetEndDate(2020, 12, 31);
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
SetUniverseSelection(new ManualUniverseSelectionModel(
QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA)));
AddAlpha(new SEC13FCrowdingAlphaModel());
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
}
}
public class SEC13FCrowdingAlphaModel : AlphaModel
{
// Count a quarter only after its 45-day filing deadline has passed.
private static readonly TimeSpan FilingDeadline = TimeSpan.FromDays(45);
private readonly Dictionary<Symbol, Symbol> _holdings = new();
private readonly Dictionary<Symbol, Dictionary<DateTime, HashSet<int>>> _managers = new();
private readonly HashSet<(Symbol, DateTime)> _emitted = new();
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var insights = new List<Insight>();
foreach (var (holdingsSymbol, point) in data.Get<SEC13FHoldings>())
{
var equity = holdingsSymbol.Underlying;
if (!_managers.TryGetValue(equity, out var byPeriod))
{
_managers[equity] = byPeriod = new Dictionary<DateTime, HashSet<int>>();
}
foreach (var holding in point.OfType<SEC13FHolding>().Where(holding =>
holding.FormType == "13F-HR" && holding.AmountType == "SH" &&
!holding.PutCall.HasValue &&
algorithm.Time <= holding.PeriodEnd + FilingDeadline))
{
if (!byPeriod.TryGetValue(holding.PeriodEnd, out var managers))
{
byPeriod[holding.PeriodEnd] = managers = new HashSet<int>();
}
managers.Add(holding.ManagerCik);
}
var closed = byPeriod.Keys.Where(p => algorithm.Time >= p + FilingDeadline)
.OrderBy(p => p).ToList();
if (closed.Count < 2 || !_emitted.Add((equity, closed[^1])))
{
continue;
}
var latest = byPeriod[closed[^1]].Count;
var previous = byPeriod[closed[^2]].Count;
if (latest == previous)
{
continue;
}
algorithm.Log($"{algorithm.Time:yyyy-MM-dd} {equity.Value}: {previous} -> {latest} managers");
var direction = latest > previous ? InsightDirection.Up : InsightDirection.Down;
insights.Add(Insight.Price(equity, TimeSpan.FromDays(30), direction));
}
return insights;
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var security in changes.AddedSecurities)
{
_holdings[security.Symbol] = algorithm.AddData<SEC13FHoldings>(security.Symbol).Symbol;
}
foreach (var security in changes.RemovedSecurities)
{
if (_holdings.Remove(security.Symbol, out var holdingsSymbol))
{
algorithm.RemoveSecurity(holdingsSymbol);
}
}
}
}