Back

SMA and RollingWindow

Hello,

So, The following algorithm is trying to trade based on following conditions:

Long: if the price breaks above the 20 SMA and slope of 200 SMA is positive

Sell: if the price breaks below the 20 SMA

The stop loss is set to 1%

Questions:

1. how can I eliminate the fee structure when I have rolling window?

2. how does the rolling window indicator data points affected my returns? I am only using the first two data points but if I change `self.smaWin = RollingWindow[IndicatorDataPoint](2)` to `self.smaWin = RollingWindow[IndicatorDataPoint](200)` the results are worse. Is it because it will first fill up the window with 200 points and then try to perform everything afterwards? Specifically, my slope will be performed after 200 hours instead of 2 hours?

3. I followed https://www.quantconnect.com/forum/discussion/4497/adding-a-sma-indicator/p1 where line 53, he is getting the price, but I get `

Runtime Error: AttributeError : 'NoneType' object has no attribute 'Price'
at OnData in main.py:line 71
:: price = self.window[0].Price
AttributeError : 'NoneType' object has no attribute 'Price'

4. The drawdown in Overview is Max drawdown?

Thanks

# https://www.quantconnect.com/forum/discussion/4497/adding-a-sma-indicator/p1

from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Data.Market import TradeBar

### <summary>
### Using rolling windows for efficient storage of historical data; which automatically clears after a period of time.
### </summary>
### <meta name="tag" content="using data" />
### <meta name="tag" content="history and warm up" />
### <meta name="tag" content="history" />
### <meta name="tag" content="warm up" />
### <meta name="tag" content="indicators" />
### <meta name="tag" content="rolling windows" />
class RollingWindowAlgorithm(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(2019,5,15) #Set Start Date
self.SetCash(1000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.AddEquity("SPY", Resolution.Hour)

self.Securities["SPY"].FeeModel = ConstantFeeModel(0)
# Creates a Rolling Window indicator to keep the 2 TradeBar
self.window = RollingWindow[TradeBar](1) # For other security types, use QuoteBar

# Creates an indicator and adds to a rolling window when it is updated
self.EMA("SPY", 200, Resolution.Hour).Updated += self.SmaUpdated
self.smaWin = RollingWindow[IndicatorDataPoint](2)

# create a 20 day exponential moving average
# Creates an indicator and adds to a rolling window when it is updated
self.fast = self.EMA("SPY", 20, Resolution.Hour)
self.fast.Updated += self.FastUpdated
self.fastWin = RollingWindow[IndicatorDataPoint](20)


def SmaUpdated(self, sender, updated):
'''Adds updated values to rolling window'''
self.smaWin.Add(updated)

def FastUpdated(self, sender, updated):
'''Adds updated values to rolling window'''
self.fastWin.Add(updated)


def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''

# Add SPY TradeBar in rollling window
self.window.Add(data["SPY"])

# Wait for windows to be ready.
if not (self.window.IsReady and self.smaWin.IsReady): return

currSma = self.smaWin[0] # Current SMA had index zero.
pastSma = self.smaWin[1]
slope = currSma.Value - pastSma.Value

holdings = self.Portfolio["SPY"].Quantity
price = self.window[0].Price
long_condition = price > self.fast.Current.Value and slope > 0
# we only want to go long if we're currently short or flat
if holdings <= 0:
if long_condition:
quantity = self.CalculateOrderQuantity("SPY", 1.0)
self.MarketOrder("SPY", quantity)
self.StopMarketOrder("SPY", -quantity, self.Securities["SPY"].Price*0.99)



# we only want to liquidate if we're currently long
# if the fast is less than the slow we'll liquidate our long
if holdings > 0 and price < self.fast.Current.Value:
self.Liquidate("SPY")

Update Backtest







0

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.


Hey Amulya,

1. Correct me if I am misunderstanding your question, but the fee structure is not related to rolling windows. The fees are determined by the security we are trading, the number of trades being place and whether we are using margin.

2.  Since the algorithm only accesses the most recent two SMA values

currSma = self.smaWin[0] # Current SMA
pastSma = self.smaWin[1] # Previous SMA

There will be no difference between using a window length of 200 and 2, besides the fact that the 200 window length will take longer to warm up, slightly delaying the start of trading.

Make sure to check that indicators are ready before we add them to our window.

def SmaUpdated(self, sender, updated):
'''Adds updated values to rolling window'''
if self.slow.IsReady:
self.smaWin.Add(updated)

def FastUpdated(self, sender, updated):
'''Adds updated values to rolling window'''
if self.fast.IsReady:
self.fastWin.Add(updated)


3. We need to check if bar data exists at the current time slice before trying to access it. Sometimes bar data can be missing, leading to a NoneType when accessing the bar.

def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''

if not data.Bars.ContainsKey("SPY"):
return

# Add SPY TradeBar in rolling window
self.window.Add(data.Bars["SPY"])

....


4. You are correct. The drawdown in overview is the maximum drawdown of the algorithm during the backtesting period.

Best
Rahul

0

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.


Thank you Rahul for the answers.

1. Since, the drawdown, reported in Overview, is the maximum drawdown, I would like to find where it is occurring. Now, quantconnect has the maximum of 4000 points to be plotted. As you can see that I have hourly chart, it will be great if you can advise be on a way to see where these drawdowns are occurring. I tried to write in in logs but the file was too big and I was stuck. That means that I can do it in chunks. But the plot is still not showing what is happening to `equity` on hourly basis.

2. May I know what is the validity of the StopMarketOrder()? Is it valid for a day or until it is hit?

Thanks

0

1. You can see this on the report created for a backtest.



2. It is good until canceled
0

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.


Update Backtest





0

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.


Loading...

This discussion is closed