Hello everyone,
I'm new to Quantconnect and I feel a little lost as I still don't know how many things work after having read the documentation. I'm trying to do something very simple for my first test algorithm. It should buy AAPL if the current price is lower than the previous day's closing price and sell it if it reaches a higher price than it was bought for. But I don't know how to get that closing price so I can compare them. I get an error saying my bars object has no .close property. How to do that correctly?
Thank you very much for your help.
Kind Regards,
Christian Lauer
Christian Lauer
class BasicTemplateAlgorithm(QCAlgorithm):    def Initialize(self):       # Set the cash we'd like to use for our backtest       # This is ignored in live trading       self.SetCash(100000)             # Start and end dates for the backtest.       # These are ignored in live trading.       self.SetStartDate(2007,1,1)       self.SetEndDate(2007,3,3)             # Add assets you'd like to see       self.aapl = self.AddEquity("aapl", Resolution.Second).Symbol             self.bars = self.History("aapl", TimeSpan.FromDays(3), Resolution.Daily)             self.SetWarmUp(200)          def OnData(self, slice):       # Simple buy and hold template       if not self.Portfolio.Invested and self.bars.Close[2] > self.price:          self.SetHoldings(self.aapl, 1)          self.Debug("numpy test >>> print numpy.pi: " + str(np.pi))                if portfolio["aapl"].price < Securities["aapl"].Price:          self.SetHoldings(self.aapl, 0)
Alexandre Catarino
By the description, it looks like the strategy needs to use the rolling window feature:
# In Initialize # Creates a Rolling Window indicator to keep the 2 TradeBar self.window = RollingWindow[TradeBar](2) # In OnData # Add SPY TradeBar in rollling window self.window.Add(data["SPY"]) # Wait for windows to be ready. if not (self.window.IsReady): return currBar = self.window[0] # Current bar had index zero. pastBar = self.window[1] # Past bar has index one.
In the attached backtest, we also show how to use rolling window with indicators and our buy signal is based on a simple moving average.
Christian Lauer
Hello Alexandre,
thank you very much for your answer. These rolling windows seem to be exactly what I need. For what I have in mind I need data of different resolutions of the same stock though. How to accomplish that? If I've make two rolling windows and use
self.AddEquity("SPY", Resolution.Daily)
self.AddEquity("SPY", Resolution.Second)
in initialilize how to I change self.window.Add(data["SPY"]) if I want one of the resolutions?
Kind regards,
Christian Lauer
Alexandre Catarino
We cannot subscribe to more than one resolution (and market).
When we want to work with more than one resolution, we need to use consolidators, where we subscribe to higher resolution data and consolidate into lower resolution.
The consolidated bars will arrive at an event handler that we define. There we will add the daily bars in the correspondent rolling window:
# In Initialize self.AddEquity("SPY", Resolution.Second) consolidator = TradeBarConsolidator(timedelta(1)) consolidator.DataConsolidated += self.OnDailyData self.SubscriptionManager.AddConsolidator("SPY", consolidator) self.daily = RollingWindow[TradeBar](2) self.window = RollingWindow[TradeBar](2) # Add daily bar to daily rolling window def OnDailyData(self, sender, bar): self.daily.Add(bar) # Add second bar to window rolling window def OnData(self, data): self.window.Add(data["SPY"])
Christian Lauer
from QuantConnect.Data.Market import TradeBar
from datetime import timedelta
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2013,10,1) #Set Start Date
self.SetEndDate(2013,11,1) #Set End Date
self.SetCash(100000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.AddEquity("SPY", Resolution.Second)
consolidator = TradeBarConsolidator(timedelta(1))
consolidator.DataConsolidated += self.OnDailyData
self.SubscriptionManager.AddConsolidator("SPY", consolidator)
self.daily = RollingWindow[TradeBar](2)
self.window = RollingWindow[TradeBar](2)
# Add daily bar to daily rolling window
def OnDailyData(self, sender, bar):
self.daily.Add(bar)
# Add second bar to window rolling window
def OnData(self, data):
self.window.Add(data["SPY"])
if not (self.window.IsReady and self.daily.IsReady): return
currBar = self.window[0]
yesterdayc = self.daily[1].close
if not self.Portfolio.Invested and currBar<yesterdyc:
self.SetHoldings("SPY", 1)
Hello Alexandre,
thank you for your quick answer! I've copied the code but I get an error. What have I done wrong?
Error: Object reference not set to an instance of an object Stack Trace
Jared Broad
Please post the backtest @Christian for help to debug it.
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.
Alexandre Catarino
In the code above, the algorithm class is missing. We want the Close of the current bar (currBar = self.window[0].Close) to compare with the close of the previous bar (yesterdayc = self.daily[1].Close).
Christian Lauer
Thank you for your help again. I've tried to implent a sell signal but I get another strange error now.
from QuantConnect.Data.Market import TradeBar from datetime import timedelta class MyAlgorithm(QCAlgorithm): def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2013,10,1) #Set Start Date self.SetEndDate(2013,11,1) #Set End Date self.SetCash(100000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY", Resolution.Second) consolidator = TradeBarConsolidator(timedelta(1)) consolidator.DataConsolidated += self.OnDailyData self.SubscriptionManager.AddConsolidator("SPY", consolidator) self.daily = RollingWindow[TradeBar](2) self.window = RollingWindow[TradeBar](2) # Add daily bar to daily rolling window def OnDailyData(self, sender, bar): self.daily.Add(bar) # Add second bar to window rolling window def OnData(self, data): self.window.Add(data["SPY"]) if not (self.window.IsReady and self.daily.IsReady): return currBar = self.window[0].Close yesterdayc = self.daily[1].Close if not self.Portfolio.Invested and currBar<yesterdayc: self.SetHoldings("SPY", 1) if portfolio["SPY"].Price *1.01< Securities["SPY"].Price: self.SetHoldings("SPY", 0)
14 | 11:31:25:
Algorithm.Initialize() Error: Loader.TryCreatePythonAlgorithm(): Unable to import python module ./cache/algorithm/main.pyc. LoadLibrary Try re-building algorithm. Stack Trace: at QuantConnect.Lean.Engine.Setup.BacktestingSetupHandler.CreateAlgorithmInstance (QuantConnect.Packets.AlgorithmNodePacket algorithmNodePacket, System.String assemblyPath) [0x00061] in <80689db089f84327a006ec7abec7cad3>:0
at QuantConnect.Lean.Engine.Engine.Run (QuantConnect.Packets.AlgorithmNodePacket job, QuantConnect.Lean.Engine.AlgorithmManager manager, System.String assemblyPath) [0x000e0] in <80689db089f84327a006ec7abec7cad3>:0 (Open Stacktrace)
15 | 11:31:25:
Your log was successfully created and can be retrieved from: https://www.quantconnect.com/backtest/35524/646286/d840c2b00121b525baee7121d9dc67db-log.txt
Christian Lauer
Could someone please help me? Even though I have no idea what causes this error, I don't think it should be difficult to fix : )
Alexandre Catarino
We couldn't reproduce that error, but this line have some issues:
if portfolio["SPY"].Price *1.01< Securities["SPY"].Price:
First, Portfolio and Securities are class attributes, so we need to refer to them with self.: self.Portfolio and self.Securities.
Price in both cases refer to the same value, therefore that expression is always false.
Finally, we cannot multiply decimal.decimal (Price) by float (1.01), We need to convert them:
import decimal as d factor = d.Decimal(1.01)
Christian Lauer
Hello Alexandre,
thank you for your quick reply. Now I have a problem with comments. I've implented
self.Debug(str(self.Securities["SPY"].Price)","str(currBar))
but I'm told this is ínvalid syntax.
Thank you for your help.
Kind regards,
Christian Lauer
from QuantConnect.Data.Market import TradeBar from datetime import timedelta from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * import decimal as d class MyAlgorithm(QCAlgorithm): def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2013,10,1) #Set Start Date self.SetEndDate(2013,10,8) #Set End Date self.SetCash(100000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY", Resolution.Second) consolidator = TradeBarConsolidator(timedelta(1)) consolidator.DataConsolidated += self.OnDailyData self.SubscriptionManager.AddConsolidator("SPY", consolidator) self.daily = RollingWindow[TradeBar](2) self.window = RollingWindow[TradeBar](2) # Add daily bar to daily rolling window def OnDailyData(self, sender, bar): self.daily.Add(bar) # Add second bar to window rolling window def OnData(self, data): self.window.Add(data["SPY"]) factor = d.Decimal(1.01) if not (self.window.IsReady and self.daily.IsReady): return currBar = self.window[0].Close yesterdayc = self.daily[1].Close if not self.Portfolio.Invested and currBar<yesterdayc: self.SetHoldings("SPY", 1) self.Debug(str(self.Securities["SPY"].Price)","str(currBar)) if self.Securities["SPY"].Price *factor< currBar: self.SetHoldings("SPY", 0)
Alexandre Catarino
# We can use '+' for string concat in python self.Debug(str(self.Securities["SPY"].Price) + "," + str(currBar))
Christian Lauer
Hello Alexandre,
thank you for your help again. Now there's still the issue that, as you pointed out, I compare the same price. I used self.portfolio["SPY"].price because I thought this would give me the price of the stock in the portfolio for which it was bought. As this is not the case, which attribute is the right one for this?
Kind regards,
Christian Lauer
Jared Broad
Christian Lauer the Portfolio is a collection of SecurityHolding objects indexed by symbol.
You can see all the security holding properties here:
I think they are case sensitive so you'll have to use "AveragePrice" -- this is the avg cost of your holdings,
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.
Christian Lauer
Thank you for your answer, Jared.
I have now added another consolidator for minute resolution and scheduled an event for buying. Some backtests work fine now, on others I get an error, though.
Thank you for your help.
Kind regards,
Christian Lauer
Runtime Error: Python.Runtime.PythonException: AttributeError : 'NoneType' object has no attribute 'Close'
at Python.Runtime.PyObject.Invoke (Python.Runtime.PyTuple args, Python.Runtime.PyDict kw) [0x00033] in <14452d8e618b4a588d1da22cca9cdbfe>:0
at Python.Runtime.PyObject.InvokeMethod (System.String name, Python.Runtime.PyTuple args, Python.Runtime.PyDict kw) [0x00007] in <14452d8e618b4a588d1da22cca9cdbfe>:0
at Python.Runtime.PyObject.TryInvokeMember (System.Dynamic.InvokeMemberBinder binder, System.Object[] args, System.Object& result) [0x0003e] in <14452d8e618b4a588d1da22cca9cdbfe>:0
at (wrapper dynamic-method) System.Object:CallSite.Target (System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,object,QuantConnect.Data.Slice)
at QuantConnect.AlgorithmFactory.Python.Wrappers.AlgorithmPythonWrapper.OnData (QuantConnect.Data.Slice slice) [0x000c6] in <c3e0e862262f416c8521641e96d97b9d>:0
at QuantConnect.Lean.Engine.AlgorithmManager.Run (QuantConnect.Packets.AlgorithmNodePacket job, QuantConnect.Interfaces.IAlgorithm algorithm, QuantConnect.Lean.Engine.DataFeeds.IDataFeed feed, QuantConnect.Lean.Engine.TransactionHandlers.ITransactionHandler transactions, QuantConnect.Lean.Engine.Results.IResultHandler results, QuantConnect.Lean.Engine.RealTime.IRealTimeHandler realtime, QuantConnect.Lean.Engine.Server.ILeanManager leanManager, System.Threading.CancellationToken token) [0x012d0] in <bf6d7e74e85a4976b81fd6609e403cea>:0 (Open Stacktrace)
from QuantConnect.Data.Market import TradeBar from datetime import timedelta from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * import decimal as d class MyAlgorithm(QCAlgorithm): def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2013,05,1) #Set Start Date self.SetEndDate(2013,07,19) self.SetCash(100000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY", Resolution.Second) consolidator = TradeBarConsolidator(timedelta(1)) consolidator.DataConsolidated += self.OnDailyData self.SubscriptionManager.AddConsolidator("SPY", consolidator) consolidatorm = TradeBarConsolidator(60) consolidatorm.DataConsolidated += self.OnMinuteData self.SubscriptionManager.AddConsolidator("SPY", consolidatorm) self.daily = RollingWindow[TradeBar](2) self.minute = RollingWindow[TradeBar](2) self.window = RollingWindow[TradeBar](2) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 31), Action(self.One)) # Add daily bar to daily rolling window def OnDailyData(self, sender, bar): self.daily.Add(bar) def OnMinuteData(self, sender, bar): self.minute.Add(bar) def One(self): if not (self.window.IsReady and self.daily.IsReady and self.minute.IsReady): return currBar = self.window[0].Close yesterdayc = self.daily[1].Close minuteBarC = self.minute[1].Close minuteBar0 = self.minute[1].Open self.Debug(str(self.Securities["SPY"].Price) + "," + str(currBar)+str(minuteBar0)+str(minuteBarC)) if not self.Portfolio.Invested and currBar<yesterdayc and minuteBar0<minuteBarC: self.SetHoldings("SPY", 1) # Add second bar to window rolling window def OnData(self, data): self.window.Add(data["SPY"]) if not (self.window.IsReady): return self.Debug("haha") factor = d.Decimal(1.01) currBar = self.window[0].Close if self.Portfolio["SPY"].AveragePrice *factor< currBar: self.SetHoldings("SPY", 0)
Alexandre Catarino
Please add a check for None, in OnData:
def OnData(self, data): if data["SPY"] is None : return
since you are trying to get the Close from a None that was added in the rolling window.
Christian Lauer
Hello Alexandre,
thank you for your help again. When I run a backtest from May to July 2013, I get an error on one day saying my buying power was insufficient. I thought this was caused maybe because there somehow was an existing order so that I got two orders for a long position. I've added a line to only order if SPY is not in my open orders but I still get that error. What is the problem?
Kind regards,
Christian Lauer
from QuantConnect.Data.Market import TradeBar from datetime import timedelta from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * import decimal as d class MyAlgorithm(QCAlgorithm): def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2013,05,1) #Set Start Date self.SetEndDate(2013,07,19) self.SetCash(100000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY", Resolution.Second) consolidator = TradeBarConsolidator(timedelta(1)) consolidator.DataConsolidated += self.OnDailyData self.SubscriptionManager.AddConsolidator("SPY", consolidator) consolidatorm = TradeBarConsolidator(60) consolidatorm.DataConsolidated += self.OnMinuteData self.SubscriptionManager.AddConsolidator("SPY", consolidatorm) self.daily = RollingWindow[TradeBar](2) self.minute = RollingWindow[TradeBar](2) self.window = RollingWindow[TradeBar](2) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 31), Action(self.One)) # Add daily bar to daily rolling window def OnDailyData(self, sender, bar): self.daily.Add(bar) def OnMinuteData(self, sender, bar): self.minute.Add(bar) def One(self): if not (self.window.IsReady and self.daily.IsReady and self.minute.IsReady): return openOrders = self.Transactions.GetOpenOrders() currBar = self.window[0].Close yesterdayc = self.daily[1].Close minuteBarC = self.minute[1].Close minuteBar0 = self.minute[1].Open self.Debug(str(self.Securities["SPY"].Price) + "," + str(currBar)+str(minuteBar0)+str(minuteBarC)) if not self.Portfolio.Invested and currBar<yesterdayc and minuteBar0<minuteBarC and "SPY" not in openOrders: self.SetHoldings("SPY", 1) # Add second bar to window rolling window def OnData(self, data): if data["SPY"] is None: return self.window.Add(data["SPY"]) if not (self.window.IsReady): return self.Debug("haha") factor = d.Decimal(1.01) currBar = self.window[0].Close if self.Portfolio["SPY"].AveragePrice *factor< currBar: self.SetHoldings("SPY", 0)
Jared Broad
Christian Lauer please where possible attach the backtest not a code snippet to make debugging easier.
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.
Christian Lauer
I'm sorry for the inconvenience. Here's the backtest.
Christian Lauer
I thought if I continued working on the algorithm, I'd maybe find out the problem by myself. But I've got another in addition now. I've implented a sell signal and scheduled a function to close my short positions at the end of each day. But this is done only on the next day after more shares have been shorted. Could someone help me please?
Kind regards,
Christian Lauer
Christian Lauer
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!