September 6, 2023
The email continued:
According to thinkorswim source code, the ADX of LYTS does not exceed 30. Let’s take the last 15 daily bars of LYTS as an example. OHLC bar chart extracted from thinkorswim and confirmed with IBKR data. Based on these, the ADX(14, Wilders) calculation for day 1 of the Boomer buy setup (August 30) shows that ADX is much less than 30, thus failing the H&R criteria for day 1:
also, ADX value is displayed in Small page for SwingTradeBot September 1st (30.44) is different from the thinkorswim ADX value (29.38).
How did swingtradebot find out that the ADX was over 30 on August 30th? Why is the ADX different on September 1st?
Next week, when I get back from vacation, I’m going to have to dig into my code to see what’s going on.but I just checked StockCharts.com and their ADX is 29.94 (versus TradingView’s ADX is 29.38). My numbers are usually the same or close to theirs because they adjust the data for dividends (as does SwingTradeBot).Most other charting services don’t – I wrote about some of that here https://swingtradebot.com/topics/11422-beware-of-charts-which-have-not-been-adjusted-for-dividends
I’ll let you know what I find.
I tested almost every value calculated by SwingTradeBot. In almost all cases, these tests show that “the expected value X equals Y”. But for the ADX value, my test was something like: “Expect ADX to be in the 0.75 range of 28.41” and then there is a comment saying “stockcharts.com puts this value at 28.41”
This reminds me that when I was writing ADX calculations years ago, I couldn’t get my values to exactly match what I had seen elsewhere.I believe that’s because My tests did not use enough days of data to get reliable ADX values. ADX has a fairly complex formula that includes a lot of data smoothing. Here is what StockCharts.com says about ADX:
Above is an example spreadsheet with all calculations involved.There is a calculation gap of 119 days because Absorption smoothing takes about 150 cycles. ADX/DMI enthusiasts can click here to download the spreadsheet and view the Gory details.It is important to understand all the smoothing effects involved in the ADX, +DI, and -DI calculations. Due to Wilder’s smoothing technique, it may take about 150 data cycles to obtain the true ADX value. Wilder uses a similar smoothing technique in his RSI and Average True Range calculations. The ADX value using only 30 historical period data does not match the ADX value using 150 historical period data. ADX values for 150 days or more of data will remain consistent
- I have some mistakes/misunderstandings in my code. I’m generating wrong values for the first day of the stock’s true range. I now correctly set the value to zero. In my directional movement index (DX) code, I forgot to take the absolute value of the calculation, so in some cases the value is negative instead of positive.
- After making these changes The values generated by my code exactly match the source spreadsheet! (As mentioned above, these values are not always equal until day 150 or so)
- I regenerated the data for the relevant raw stock (LYTS), but the values still don’t match the StockCharts or ThinkOrSwim values.
Here are the LYTS ADX values:
My thoughts on the above data:
- My changes to the calculation didn’t have a significant impact on the final ADX value.
- I find it curious (to say the least!) My algorithm matches StockCharts’ ADX spreadsheet, but it doesn’t match what StockCharts’ actual system generates. They seem to use a different approach in the system***
- Same value for StockCharts and Think or Swim Until August 25th, the ex-dividend date of LYTS!
- By definition, 25 is the level of interest in the ADX, as Wilder sees it as the threshold for a strong trend.
- Hit & Run Trading (like Boomer Buy) tends to use an ADX value of 30 for setups. through that lens SwingTradeBot’s data differs by only one day – in this case it will alert you one day in advance data from other sites.
Let’s take 5/0.017 and 5/0.02 as an example. The first result was 294.11 and the second was 250! My code keeps all those decimal places, but if the algorithm rounded 0.017 to 0.02, the result would be very different! )
Again from the ADX article on StockCharts:
At its most basic level, the Average Directional Index (ADX) can be used to determine whether a security is in a trend. This decision helps traders choose between a trend following system or a non-trend following system. Wilder believes that when ADX is above 25, there is a strong trend; when ADX is below 20, there is no trend. There seems to be a gray area between 20 and 25. As mentioned above, chartists may need to adjust settings to improve sensitivity and signal. ADX also has a fair amount of lag due to all the smoothing techniques. Many technical analysts use 20 as a key level for ADX.
More generally, I would reiterate that ADX is a lagging indicator.If you look at the graph, you’ll see In fact, it started trending higher on Aug. 17, when it gapped higher after the earnings report. ADX didn’t show this until it broke 25 6 days later, it took a few more days to break 30
While ADX is useful, we must realize that It is the derivative of the derivative of the derivative – hence its hysteresis. That’s why I’ve written this little note on the site since day one:
My takeaways from all this are:
- Over the years, I’ve grown to realize that stock market data is sometimes not “real.” One place may adjust for dividends, one data provider may set a closing price at 4pm while another uses a 4:15 price, or the indicator may use a slightly different algorithm.
- Being too precise can backfire. I’ve seen this on SwingTradeBot when people get too preoccupied with finding exact letter grades (I discussed this a bit in the comments here). I’ve also seen people place limit orders that didn’t get filled, and then they missed out on a huge move because they weren’t willing to pay just a few cents.
- While I’m still a bit curious as to why my numbers don’t match up with StockChart’s live data, I am very satisfied that the values generated by my code exactly match their ADX spreadsheet. I don’t think it’s worth spending more time tweaking the code as what it generates is “accurate enough”