Hi there,
I have a strategy that uses pre-defined price data for various futures contracts that works fine, but when I update the algorithm to use the Quantconnect continuous futures, the algorithm gives an error about leverage:
Runtime Error: Futures do not allow specifying a leveraged target, since they are traded using margin which already is leveraged. Possible target buying power goes from -1 to 1, target provided is: -1.597480554358317825 in FutureMarginModel.cs:line 118
Here's the code:
from math import ceil
from AlgorithmImports import *
class ReturnsSignalMomentum(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 1, 1)
self.SetCash(100000)
self.ES_contract = self.AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.OpenInterest,
contractDepthOffset = 0)
self.GC_contract = self.AddFuture(Futures.Metals.Gold,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.OpenInterest,
contractDepthOffset = 0)
self.CL_contract = self.AddFuture(Futures.Energies.CrudeOilWTI,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.OpenInterest,
contractDepthOffset = 0)
self.symbols = [
self.ES_contract.Symbol,
self.GC_contract.Symbol,
self.CL_contract.Symbol
]
#self.symbols = [
# "CME_AD1", # Australian Dollar Futures, Continuous Contract #1
# "CME_BP1", # British Pound Futures, Continuous Contract #1
# "CME_EC1", # Euro FX Futures, Continuous Contract #1
# "CME_JY1", # Japanese Yen Futures, Continuous Contract #1
# "ICE_DX1", # US Dollar Index Futures, Continuous Contract #1
# "CME_NQ1", # E-mini NASDAQ 100 Futures, Continuous Contract #1
# "EUREX_FDAX1", # DAX Futures, Continuous Contract #1
# "CME_ES1", # E-mini S&P 500 Futures, Continuous Contract #1
# "CME_GC1", # Gold Futures, Continuous Contract
# "CME_SI1", # Silver Futures, Continuous Contract
# "ICE_CC1", # Cocoa Futures, Continuous Contract
# "ICE_KC1", # Coffee C Futures, Continuous Contract
# "ICE_SB1", # Sugar No. 11 Futures, Continuous Contract
# "CME_S1", # Soybean Futures, Continuous Contract
# "CME_W1", # Wheat Futures, Continuous Contract
# "CME_C1", # Corn Futures, Continuous Contract
# "CME_LC1", # Live Cattle Futures, Continuous Contract
# "CME_FC1", # Feeder Cattle Futures, Continuous Contract
# "CME_ZB1",
# "CME_ZQ1",
# "CME_NG1", # Natural Gas (Henry Hub) Physical Futures, Continuous Contract
# "CME_CL1",
# "ICE_O1" # Heating Oil Futures, Continuous Contract
# ]
period = 100
self.SetWarmUp(period)
self.dch = {}
self.atr = {}
for symbol in self.symbols:
#data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)
data = self.History(symbol, 252, Resolution.Daily)
#data.SetFeeModel(CustomFeeModel())
#data.SetLeverage(10)
self.dch[symbol] = self.DCH(symbol, period, Resolution.Daily)
self.atr[symbol] = self.ATR(symbol, 10, Resolution.Daily)
def OnData(self, data):
if self.IsWarmingUp: return
dollar_pos_size = {}
equity = self.Portfolio.TotalPortfolioValue
long = []
short = []
for symbol in self.symbols:
if self.Securities[symbol].GetLastData() and (self.Time.date() - self.Securities[symbol].GetLastData().Time.date()).days >= 5:
continue
if symbol not in data or not data[symbol]: continue
if not self.dch[symbol].IsReady or not self.atr[symbol].IsReady: continue
price = data[symbol].Price
atr = self.atr[symbol].Current.Value
upper_band = self.dch[symbol].UpperBand.Current.Value
lower_band = self.dch[symbol].LowerBand.Current.Value
# Close position.
if self.Portfolio[symbol].IsLong:
if price < lower_band:
#if price < (upper_band - 2*atr):
self.Liquidate(symbol)
if self.Portfolio[symbol].IsShort:
if price > upper_band:
#if price > (lower_band + 2*atr):
self.Liquidate(symbol)
# Calculate positon size.
#unit_size = (equity * 0.1 * 0.02) / (atr*4)
unit_size = (equity * 0.1 * 0.02) / (atr)
if price > upper_band:
if not self.Portfolio[symbol].IsLong:
long.append(symbol)
dollar_pos_size[symbol] = unit_size * price
elif price < lower_band:
if not self.Portfolio[symbol].IsShort:
short.append(symbol)
dollar_pos_size[symbol] = unit_size * price
# Rebalance opened positions and open new ones.
for symbol in long + short:
percentage = dollar_pos_size[symbol] / equity
if symbol in long: self.SetHoldings(symbol, percentage)
if symbol in short: self.SetHoldings(symbol, -percentage)
# Custom fee model.
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))
Besides changing the data source, I also changed the method to access the data from AddData to History:
#data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)
data = self.History(symbol, 252, Resolution.Daily)
Just wondering, if there is a difference between how price data is returned from AddData versus History.
Please advise.
David
Louis Szeto
Hi David
The default future margin model/buying power model does not allow leverage. To override this behavior, you may set your own buying power model with leverage with a custom security initializer:
Note that your algorithm also had an error in ordering with the continuous future's canonical symbol (docs). You should order with:
As per the difference between AddData and History, AddData is adding a data subscription to a data source, in which its data is received in form of Slice with OnData method by the EndTime of each data slice. while History method received a one-time Slice collection of historical data without the need of subscribing to the data.
Best
Louis
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
David Lelong
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!