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:

  1. from math import ceil
  2. from AlgorithmImports import *
  3. class ReturnsSignalMomentum(QCAlgorithm):
  4. def Initialize(self):
  5. self.SetStartDate(2022, 1, 1)
  6. self.SetCash(100000)
  7. self.ES_contract = self.AddFuture(Futures.Indices.SP500EMini,
  8. dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
  9. dataMappingMode = DataMappingMode.OpenInterest,
  10. contractDepthOffset = 0)
  11. self.GC_contract = self.AddFuture(Futures.Metals.Gold,
  12. dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
  13. dataMappingMode = DataMappingMode.OpenInterest,
  14. contractDepthOffset = 0)
  15. self.CL_contract = self.AddFuture(Futures.Energies.CrudeOilWTI,
  16. dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
  17. dataMappingMode = DataMappingMode.OpenInterest,
  18. contractDepthOffset = 0)
  19. self.symbols = [
  20. self.ES_contract.Symbol,
  21. self.GC_contract.Symbol,
  22. self.CL_contract.Symbol
  23. ]
  24. #self.symbols = [
  25. # "CME_AD1", # Australian Dollar Futures, Continuous Contract #1
  26. # "CME_BP1", # British Pound Futures, Continuous Contract #1
  27. # "CME_EC1", # Euro FX Futures, Continuous Contract #1
  28. # "CME_JY1", # Japanese Yen Futures, Continuous Contract #1
  29. # "ICE_DX1", # US Dollar Index Futures, Continuous Contract #1
  30. # "CME_NQ1", # E-mini NASDAQ 100 Futures, Continuous Contract #1
  31. # "EUREX_FDAX1", # DAX Futures, Continuous Contract #1
  32. # "CME_ES1", # E-mini S&P 500 Futures, Continuous Contract #1
  33. # "CME_GC1", # Gold Futures, Continuous Contract
  34. # "CME_SI1", # Silver Futures, Continuous Contract
  35. # "ICE_CC1", # Cocoa Futures, Continuous Contract
  36. # "ICE_KC1", # Coffee C Futures, Continuous Contract
  37. # "ICE_SB1", # Sugar No. 11 Futures, Continuous Contract
  38. # "CME_S1", # Soybean Futures, Continuous Contract
  39. # "CME_W1", # Wheat Futures, Continuous Contract
  40. # "CME_C1", # Corn Futures, Continuous Contract
  41. # "CME_LC1", # Live Cattle Futures, Continuous Contract
  42. # "CME_FC1", # Feeder Cattle Futures, Continuous Contract
  43. # "CME_ZB1",
  44. # "CME_ZQ1",
  45. # "CME_NG1", # Natural Gas (Henry Hub) Physical Futures, Continuous Contract
  46. # "CME_CL1",
  47. # "ICE_O1" # Heating Oil Futures, Continuous Contract
  48. # ]
  49. period = 100
  50. self.SetWarmUp(period)
  51. self.dch = {}
  52. self.atr = {}
  53. for symbol in self.symbols:
  54. #data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)
  55. data = self.History(symbol, 252, Resolution.Daily)
  56. #data.SetFeeModel(CustomFeeModel())
  57. #data.SetLeverage(10)
  58. self.dch[symbol] = self.DCH(symbol, period, Resolution.Daily)
  59. self.atr[symbol] = self.ATR(symbol, 10, Resolution.Daily)
  60. def OnData(self, data):
  61. if self.IsWarmingUp: return
  62. dollar_pos_size = {}
  63. equity = self.Portfolio.TotalPortfolioValue
  64. long = []
  65. short = []
  66. for symbol in self.symbols:
  67. if self.Securities[symbol].GetLastData() and (self.Time.date() - self.Securities[symbol].GetLastData().Time.date()).days >= 5:
  68. continue
  69. if symbol not in data or not data[symbol]: continue
  70. if not self.dch[symbol].IsReady or not self.atr[symbol].IsReady: continue
  71. price = data[symbol].Price
  72. atr = self.atr[symbol].Current.Value
  73. upper_band = self.dch[symbol].UpperBand.Current.Value
  74. lower_band = self.dch[symbol].LowerBand.Current.Value
  75. # Close position.
  76. if self.Portfolio[symbol].IsLong:
  77. if price < lower_band:
  78. #if price < (upper_band - 2*atr):
  79. self.Liquidate(symbol)
  80. if self.Portfolio[symbol].IsShort:
  81. if price > upper_band:
  82. #if price > (lower_band + 2*atr):
  83. self.Liquidate(symbol)
  84. # Calculate positon size.
  85. #unit_size = (equity * 0.1 * 0.02) / (atr*4)
  86. unit_size = (equity * 0.1 * 0.02) / (atr)
  87. if price > upper_band:
  88. if not self.Portfolio[symbol].IsLong:
  89. long.append(symbol)
  90. dollar_pos_size[symbol] = unit_size * price
  91. elif price < lower_band:
  92. if not self.Portfolio[symbol].IsShort:
  93. short.append(symbol)
  94. dollar_pos_size[symbol] = unit_size * price
  95. # Rebalance opened positions and open new ones.
  96. for symbol in long + short:
  97. percentage = dollar_pos_size[symbol] / equity
  98. if symbol in long: self.SetHoldings(symbol, percentage)
  99. if symbol in short: self.SetHoldings(symbol, -percentage)
  100. # Custom fee model.
  101. class CustomFeeModel(FeeModel):
  102. def GetOrderFee(self, parameters):
  103. fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
  104. return OrderFee(CashAmount(fee, "USD"))
+ Expand

Besides changing the data source, I also changed the method to access the data from AddData to History:

  1. #data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)
  2. 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

Author

David Lelong

July 2022