CFD
Requesting Data
Introduction
Request Contract for Difference (CFD) data in your algorithm to receive a feed of contract prices in the OnData
on_data
method. QuantConnect supports CFD trading with OANDA and Interactive Brokers.
OANDA Subscriptions
To create a CFD subscription, in the Initialize
initialize
method, call the AddCfd
add_cfd
method. The AddCfd
add_cfd
method returns a Cfd
Security object, which contains a Symbol
symbol
property. Save a reference to the Symbol
symbol
so you can use it in OnData
on_data
to access the security data in the Slice
.
_symbol = AddCfd("XAUUSD").Symbol;
self._symbol = self.add_cfd("XAUUSD").symbol
To view the supported CFD contracts, see Supported Assets. For more information about the specific dataset we use for backtests, see the OANDA CFD dataset listing. To trade OANDA CFDs live, use our QuantConnect data provider.
Interactive Brokers Subscriptions
To create a CFD subscription for Interactive Brokers (IB), in the Initialize
initialize
method, call the AddCfd
add_cfd
method and set the market
parameter to Market.InteractiveBrokers
Market.INTERACTIVE_BROKERS
. The AddCfd
add_cfd
method returns a Cfd
Security object, which contains a Symbol
symbol
property. Save a reference to the Symbol
symbol
so you can use it in OnData
on_data
to access the security data in the Slice
.
_symbol = AddCfd("SPY", market: Market.InteractiveBrokers).Symbol;
self._symbol = self.add_cfd("SPY", market=Market.INTERACTIVE_BROKERS).symbol
Historical data for backtesting IB CFDs is unavailable.
In live trading, include the Interactive Brokers data provider when you deploy the algorithm to access IB CFD data. You can use this data provider for paper or real-money accounts. IB provides data for Indexes, Metals, Forex, and Global Stock CFDs. To view the Index and Forex CFD products that IB supports in live trading, see the Interactive Brokers Supported Contracts. To view the Equity CFD products, see the Products Search page on the IB website.
If you live in the EU and can't trade US ETFs due to regulation, you can trade their CFD equivalents in live mode.
var securityType = LiveMode ? SecurityType.Cfd : SecurityType.Equity; var market = LiveMode ? Market.InteractiveBrokers : Market.USA; _symbol = QuantConnect.Symbol.Create("SPY", securityType, Market.InteractiveBrokers); AddSecurity(_symbol);
security_type = SecurityType.CFD if self.live_mode else SecurityType.EQUITY market=Market.INTERACTIVE_BROKERS if self.live_mode else Market.USA self._symbol = Symbol.create("SPY", security_type, market) self.add_security(self._symbol)
Resolutions
The following table shows the available resolutions and data formats for CFD subscriptions:
Resolution | TradeBar | QuoteBar | Trade Tick | Quote Tick |
---|---|---|---|---|
Tick TICK | ||||
Second SECOND | ||||
Minute MINUTE | ||||
Hour HOUR | ||||
Daily DAILY |
The default resolution for CFD subscriptions is Resolution.Minute
Resolution.MINUTE
. To change the resolution, pass a resolution
argument to the AddCfd
add_cfd
method.
_symbol = AddCfd("XAUUSD", Resolution.Daily).Symbol;
self._symbol = self.add_cfd("XAUUSD", Resolution.DAILY).symbol
To create custom resolution periods, see Consolidating Data.
Fill Forward
Fill forward means if there is no data point for the current slice, LEAN uses the previous data point. Fill forward is the default data setting. If you disable fill forward, you may get stale fills or you may see trade volume as zero.
To disable fill forward for a security, set the fillForward
fill_forward
argument to false when you create the security subscription.
_symbol = AddCfd("XAUUSD", fillForward: false).Symbol;
self._symbol = self.add_cfd("XAUUSD", fill_forward=False).symbol
Margin and Leverage
LEAN models buying power and margin calls to ensure your algorithm stays within the margin requirements. The specific margin available depends on your brokerage destination. To change the amount of leverage you can use for a CFD contract, pass a leverage
argument to the AddCfd
add_cfd
method.
_symbol = AddCfd("XAUUSD", leverage: 35).Symbol;
self._symbol = self.add_cfd("XAUUSD", leverage=35).symbol
Data Normalization
The data normalization mode doesn't affect the data that LEAN passes to OnData
on_data
or the data from history request. If you change the data normalization mode, it won't change the outcome.
Interactive Brokers Stock CFDs apply corporate actions to the price of the asset, including paying dividends in cash to your account. This behavior is not modeled today and splits in live trading will result in price discontinuities. You should monitor the underlying Equity for events and use the underlying Equity for indicators.
Examples
The following strategy purchases ETFs when their fast moving average crosses over the slow moving average. In live mode, the strategy purchases their CFD equivalents.
public class EtfCfdSwapMovingAverageCrossAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2022, 9, 28); SetCash(100000); var tickers = new[] {"SPY", "BND", "GLD", "QQQ"}; var securityType = LiveMode ? SecurityType.Cfd : SecurityType.Equity; foreach (var ticker in tickers) { var equity = AddEquity(ticker, Resolution.Daily); equity["smaFast"] = SMA(equity.Symbol, 50); equity["smaSlow"] = SMA(equity.Symbol, 200); equity["targetVehicle"] = LiveMode ? AddCfd(ticker, Resolution.Daily, market: Market.InteractiveBrokers).Symbol : equity.Symbol; } } public override void OnData(Slice data) { foreach (var security in Securities.Values) { var targetVehicle = security["targetVehicle"] as Symbol; if ((SimpleMovingAverage)security["smaFast"] > (SimpleMovingAverage)security["smaSlow"]) { SetHoldings(targetVehicle, 0.25m); } else { SetHoldings(targetVehicle, 0m); } } } }
class EtfCfdSwapMovingAverageCrossAlgorithm(QCAlgorithm): def initialize(self): self.set_start_date(2022, 9, 28) self.set_cash(100000) tickers = ["SPY", "BND", "GLD", "QQQ"] security_type = SecurityType.CFD if self.live_mode else SecurityType.EQUITY for ticker in tickers: equity = self.add_equity(ticker, Resolution.DAILY) equity.sma_fast = self.sma(equity.symbol, 50) equity.sma_slow = self.sma(equity.symbol, 200) equity.target_vehicle = self.add_cfd(ticker, Resolution.DAILY, market=Market.INTERACTIVE_BROKERS).symbol if self.live_mode else equity.symbol def on_data(self, data: Slice): for security in self.securities.values(): if security.sma_fast > security.sma_slow: self.set_holdings(security.target_vehicle, 0.25) else: self.set_holdings(security.target_vehicle, 0)