Commitments of Traders
AvailableWeekly futures positioning by trader group, arriving at the CFTC's actual release time.
Who holds the open interest in every US futures market the CFTC reports on, every week since June 2006: commodities from the Disaggregated report, and currencies, rates, stock indices and crypto from the Traders in Financial Futures report.
Positions are as of Tuesday and usually published on Friday at 15:30 New York time. Each row reaches your algorithm at its real release time, including holiday delays and the catch-up releases after government shutdowns, so a backtest never trades on a report before it came out.
How the data works
- A row becomes available at 15:30 New York time on the third business day after its report date: the usual Friday, or later when a federal holiday or closure falls in that week, as on the CFTC's schedule.
- Releases delayed by the 2013, 2018-19 and 2025 shutdowns and the 2023 ION cyber incident arrive on their actual catch-up dates.
- Positions are futures only, in contracts. Spread positions are long and short in different months of the same market. A field the report doesn't have is None: commodities have no dealer fields, and financial futures have no producer fields.
- Load a market by its futures root (CL, NG, GC, SI, HG, ZC, ZS, ZW, LE, ES, NQ, ZN, ZB, 6E, 6J, VX, BTC and others) or by its CFTC contract code, for example "088691" for gold. markets.csv in the dataset folder lists every code.
- The Disaggregated and TFF reports were first published in 2009 and 2010, with history back to 2006. Before then, traders saw only the older Legacy report for those weeks.
- Values are as finally published. The CFTC rarely corrects one market's report after release, and those corrections are not dated separately.
Fields
13 columns| Field | Description |
|---|---|
| available_time | When the row becomes visible to an algorithm: 15:30 New York time on the release day |
| report_date | Day the positions are as of, usually a Tuesday |
| report | disaggregated (commodities) or financial (Traders in Financial Futures) |
| open_interest | Futures open interest, in contracts |
| producer_long, producer_short | Producers, merchants, processors and users (disaggregated) |
| swap_long, swap_short, swap_spread | Swap dealers (disaggregated) |
| managed_money_long, managed_money_short, managed_money_spread | CTAs, commodity pools and hedge funds (disaggregated) |
| dealer_long, dealer_short, dealer_spread | Banks and dealers on the sell side (financial) |
| asset_manager_long, asset_manager_short, asset_manager_spread | Pension funds, endowments, insurers and mutual funds (financial) |
| leveraged_long, leveraged_short, leveraged_spread | Hedge funds and CTAs (financial) |
| other_long, other_short, other_spread | Other reportable traders |
| nonreportable_long, nonreportable_short | Positions below the CFTC's reporting thresholds |
| traders | Number of reportable traders |
Example algorithm
# region imports
from AlgorithmImports import *
# endregion
from lean_platform_data import CotReport
class PositioningAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2010, 1, 1)
self.set_end_date(2021, 1, 1)
self.spy = self.add_equity("SPY", Resolution.DAILY).symbol
# A futures root (ES, GC, CL, 6E, ...) or a CFTC contract code.
self.cot = self.add_data(CotReport, "ES").symbol
self.history = RollingWindow[float](52) # a year of weekly reports
def on_data(self, slice):
if self.cot not in slice:
return
c = slice[self.cot]
net = (c.asset_manager_long - c.asset_manager_short) / c.open_interest
self.history.add(net)
if not self.history.is_ready:
return
average = sum(self.history) / self.history.count
# Hold SPY while asset managers are more net long E-mini S&P futures than their one-year average.
if net > average:
self.set_holdings(self.spy, 1)
else:
self.liquidate(self.spy)
Public data from the U.S. Commodity Futures Trading Commission. Free for backtesting on MarketsCoder.