Commodity Futures Trading Commission
Commitments of Traders
Introduction
The Commitments of Traders dataset by the Commodity Futures Trading Commission (CFTC) tracks the long and short positions that each type of trader holds in US futures markets. The data covers 942 futures markets, starts in January 1998, and is delivered on a weekly frequency. This dataset is created by processing the weekly Commitments of Traders reports.
For more information about the Commitments of Traders dataset, including CLI commands and pricing, see the dataset listing.
Requesting Data
To add CFTC Commitments of Traders 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 CFTCDataAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 1, 1)
self.set_end_date(2020, 6, 1)
self.set_cash(100000)
self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
self._legacy = self.add_data(CFTCLegacy, CFTC.Markets.E_MINI_SP_500, Resolution.DAILY).symbol
self._disaggregated = self.add_data(CFTCDisaggregated, CFTC.Markets.GOLD, Resolution.DAILY).symbol
self._tff = self.add_data(CFTCFinancialFutures, CFTC.Markets.E_MINI_SP_500, Resolution.DAILY).symbol public class CFTCDataAlgorithm : QCAlgorithm
{
private Symbol _spy, _legacy, _disaggregated, _tff;
public override void Initialize()
{
SetStartDate(2020, 1, 1);
SetEndDate(2020, 6, 1);
SetCash(100000);
_spy = AddEquity("SPY", Resolution.Daily).Symbol;
_legacy = AddData<CFTCLegacy>(CFTC.Markets.EMiniSP500, Resolution.Daily).Symbol;
_disaggregated = AddData<CFTCDisaggregated>(CFTC.Markets.Gold, Resolution.Daily).Symbol;
_tff = AddData<CFTCFinancialFutures>(CFTC.Markets.EMiniSP500, Resolution.Daily).Symbol;
}
}
Accessing Data
To get the current CFTC Commitments of Traders 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._legacy):
data_point = slice[self._legacy]
self.log(f"{self._legacy} non-commercial net at {slice.time}: {data_point.non_commercial_net}") public override void OnData(Slice slice)
{
if (slice.ContainsKey(_legacy))
{
var dataPoint = slice[_legacy];
Log($"{_legacy} non-commercial net at {slice.Time}: {dataPoint.NonCommercialNet}");
}
}
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, data_point in slice.get(CFTCDisaggregated).items():
self.log(f"{dataset_symbol} managed money net at {slice.time}: {data_point.managed_money_net}") public override void OnData(Slice slice)
{
foreach (var kvp in slice.Get<CFTCDisaggregated>())
{
var datasetSymbol = kvp.Key;
var dataPoint = kvp.Value;
Log($"{datasetSymbol} managed money net at {slice.Time}: {dataPoint.ManagedMoneyNet}");
}
}
Historical Data
To get historical CFTC Commitments of Traders data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty.
# DataFrames legacy_history_df = self.history(self._legacy, 100, Resolution.DAILY) history_df = self.history([self._legacy, self._disaggregated, self._tff], 100, Resolution.DAILY) # Dataset objects legacy_history_bars = self.history[CFTCLegacy](self._legacy, 100, Resolution.DAILY) disaggregated_history_bars = self.history[CFTCDisaggregated](self._disaggregated, 100, Resolution.DAILY) tff_history_bars = self.history[CFTCFinancialFutures](self._tff, 100, Resolution.DAILY)
// Dataset objects
var legacyHistory = History<CFTCLegacy>(_legacy, 100, Resolution.Daily);
var disaggregatedHistory = History<CFTCDisaggregated>(_disaggregated, 100, Resolution.Daily);
var tffHistory = History<CFTCFinancialFutures>(_tff, 100, Resolution.Daily);
// Slice objects
var history = History(new[] {_legacy, _disaggregated, _tff}, 100, Resolution.Daily);
For more information about historical data, see History Requests.
Supported Markets
The CFTC.Markets helper covers every market in the reports. The following table shows the accessor code you need to add some of the markets to your algorithm:
| Constant | Market |
|---|---|
CFTC.Markets.EMiniSP500CFTC.Markets.E_MINI_SP_500 | E-mini S&P 500 |
CFTC.Markets.GoldCFTC.Markets.GOLD | Gold |
CFTC.Markets.CrudeOilBrentCFTC.Markets.CRUDE_OIL_BRENT | Crude Oil, Brent |
CFTC.Markets.NaturalGasCFTC.Markets.NATURAL_GAS | Natural Gas |
CFTC.Markets.CornCFTC.Markets.CORN | Corn |
Example Applications
The Commitments of Traders dataset enables you to follow how different types of traders are positioned in the futures markets. Examples include the following strategies:
- Trading with non-commercial traders when their net position turns from short to long
- Fading a market when speculator positioning reaches a multi-year extreme
- Ranking commodities by the weekly change in speculator positions
Classic Algorithm Example
The following example algorithm buys SPY when non-commercial traders are net long the E-mini S&P 500. When they are net short, it short sells SPY.
from AlgorithmImports import *
class CFTCDataAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 1, 1)
self.set_end_date(2020, 6, 1)
self.set_cash(100000)
self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
self._legacy = self.add_data(CFTCLegacy, CFTC.Markets.E_MINI_SP_500, Resolution.DAILY).symbol
history = self.history(CFTCLegacy, self._legacy, 60, Resolution.DAILY)
self.debug(f"We got {len(history)} items from our history request")
def on_data(self, slice):
legacy = slice.get(CFTCLegacy)
if not legacy or self._legacy not in legacy:
return
net = legacy[self._legacy].non_commercial_net
if net is None:
return
# Go long when the non-commercial traders are net long the E-mini S&P 500
if net > 0:
self.set_holdings(self._spy, 1)
# Go short when they are net short
elif net < 0:
self.set_holdings(self._spy, -1) public class CFTCDataAlgorithm : QCAlgorithm
{
private Symbol _spy;
private Symbol _legacy;
public override void Initialize()
{
SetStartDate(2020, 1, 1);
SetEndDate(2020, 6, 1);
SetCash(100000);
_spy = AddEquity("SPY", Resolution.Daily).Symbol;
_legacy = AddData<CFTCLegacy>(CFTC.Markets.EMiniSP500, Resolution.Daily).Symbol;
var history = History<CFTCLegacy>(_legacy, 60, Resolution.Daily);
Debug($"We got {history.Count()} items from our history request");
}
public override void OnData(Slice slice)
{
var legacy = slice.Get<CFTCLegacy>();
if (!legacy.ContainsKey(_legacy))
{
return;
}
var net = legacy[_legacy].NonCommercialNet;
if (net == null)
{
return;
}
// Go long when the non-commercial traders are net long the E-mini S&P 500
if (net > 0)
{
SetHoldings(_spy, 1);
}
// Go short when they are net short
else if (net < 0)
{
SetHoldings(_spy, -1);
}
}
}
Framework Algorithm Example
The following example algorithm buys SPY when non-commercial traders are net long the E-mini S&P 500. When they are net short, it short sells SPY.
from AlgorithmImports import *
class CFTCFrameworkAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2020, 1, 1)
self.set_end_date(2020, 6, 1)
self.set_cash(100000)
self.universe_settings.resolution = Resolution.DAILY
# Trade SPY as the proxy of the E-mini S&P 500 futures the report covers
symbols = [Symbol.create("SPY", SecurityType.EQUITY, Market.USA)]
self.add_universe_selection(ManualUniverseSelectionModel(symbols))
# A custom alpha model that emits trade insights based on CFTC positioning data
self.add_alpha(CFTCAlphaModel(self))
# Equally invest to dissipate non-systematic capital concentration risk on individual stock
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
class CFTCAlphaModel(AlphaModel):
def __init__(self, algorithm: QCAlgorithm) -> None:
self.tradable_symbols = []
# Request the Legacy report for the E-mini S&P 500 for trade signal generation
self.cftc_symbol = algorithm.add_data(CFTCLegacy, CFTC.Markets.E_MINI_SP_500, Resolution.DAILY).symbol
# Historical data
history = algorithm.history(CFTCLegacy, self.cftc_symbol, 60, Resolution.DAILY)
algorithm.debug(f"We got {len(history)} items from our history request")
def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]:
# Skip the slices that carry no new report
points = slice.get(CFTCLegacy)
if self.cftc_symbol not in points:
return []
# Read the net position of the non-commercial traders
net = points[self.cftc_symbol].non_commercial_net
if net is None:
return []
insights = []
for symbol in self.tradable_symbols:
# Emit an up insight when the non-commercial traders are net long
if net > 0:
insights += [Insight.price(symbol, timedelta(days=7), InsightDirection.UP)]
# Emit a down insight when they are net short
elif net < 0:
insights += [Insight.price(symbol, timedelta(days=7), InsightDirection.DOWN)]
return insights
def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
for security in changes.added_securities:
self.tradable_symbols.append(security.symbol) public class CFTCFrameworkAlgorithm : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2020, 1, 1);
SetEndDate(2020, 6, 1);
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
// Trade SPY as the proxy of the E-mini S&P 500 futures the report covers
var symbols = new[] {QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)};
AddUniverseSelection(new ManualUniverseSelectionModel(symbols));
// A custom alpha model that emits trade insights based on CFTC positioning data
AddAlpha(new CFTCAlphaModel(this));
// Equally invest to dissipate non-systematic capital concentration risk on individual stock
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
}
}
public class CFTCAlphaModel : AlphaModel
{
private Symbol CFTCSymbol;
private List<Symbol> tradableSymbols = new List<Symbol>();
public CFTCAlphaModel(QCAlgorithm algorithm)
{
// Request the Legacy report for the E-mini S&P 500 for trade signal generation
CFTCSymbol = algorithm.AddData<CFTCLegacy>(CFTC.Markets.EMiniSP500, Resolution.Daily).Symbol;
// Historical data
var history = algorithm.History<CFTCLegacy>(CFTCSymbol, 60, Resolution.Daily);
algorithm.Debug($"We got {history.Count()} items from our history request");
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice)
{
var insights = new List<Insight>();
// Skip the slices that carry no new report
var points = slice.Get<CFTCLegacy>();
if (!points.ContainsKey(CFTCSymbol))
{
return insights;
}
// Read the net position of the non-commercial traders
var net = points[CFTCSymbol].NonCommercialNet;
if (net == null)
{
return insights;
}
foreach (var symbol in tradableSymbols)
{
// Emit an up insight when the non-commercial traders are net long
if (net > 0)
{
insights.Add(Insight.Price(symbol, TimeSpan.FromDays(7), InsightDirection.Up));
}
// Emit a down insight when they are net short
if (net < 0)
{
insights.Add(Insight.Price(symbol, TimeSpan.FromDays(7), InsightDirection.Down));
}
}
return insights;
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var security in changes.AddedSecurities)
{
tradableSymbols.Add(security.Symbol);
}
}
}
Data Point Attributes
The CFTC Commitments of Traders dataset provides CFTCLegacy, CFTCDisaggregated and CFTCFinancialFutures objects.
CFTCLegacy
CFTCLegacy objects have the following attributes:
CFTCDisaggregated
CFTCDisaggregated objects have the following attributes:
CFTCFinancialFutures
CFTCFinancialFutures objects have the following attributes: