Writing scans does not always go as hoped; the more complex the scan, the more likely something unintended will occur. Going forward, you will need strategies to debug and fix these problems.
Two big clues that your scan needs to be debugged are the number of results returned and the speed at which the scan runs. These two symptoms indicate very different underlying problems and must be handled in very different ways. A scan that returns too many or too few results is likely not giving you the correct results. A slow scan, on the other hand, usually has the right results, but takes far too long to give them to you very slowly.
For scans that run slowly, the clauses themselves rarely need to be corrected; it is the order of those clauses that needs to be changed. This is because the scan engine processes the clauses of your scan in order from beginning to end. It begins by filtering out stocks that don't meet the first clause, then checks the remaining stocks against the second clause to filter out any that don't meet that criteria, and so on. Each clause reduces the number of stocks left in the results.
The key point here is that the clauses at the beginning will generally be applied to a much larger number of stocks than the clauses at the end of your scan. We can use this to our advantage to improve the speed of the scan.
Some clauses take longer to process than others. Processing a clause like “[group = SP500]” is fairly quick - the scan engine simply checks to see if the stock is one of the 500 stocks in the S&P 500. On the other hand, processing a computational clause such as “[Chande Trend Meter > 80.0]” calls for some intensive number crunching, which will take much longer.
If you put the easy clause at the beginning of the scan, it can be run fairly quickly against the tens of thousands of stocks in our database, limiting your results to just 500 stocks right away. Afterwards, the more intensive Chande Trend Meter clause only has to be run against those 500 stocks. Although this will take a comparatively long time per stock, you'll be running it against a much smaller number of stocks.
The rule of thumb here is to narrow down the universe of stocks you're scanning as much as possible (and as early as possible) with clauses at the beginning of your scan that require little or no number crunching. This includes clauses that check a property of the stock (what industry it is a part of, what exchange it trades on, what groups it is a member of), but it also includes very simple calculations, such as checking whether the closing price or volume is above its average for a certain timeframe.
Once you're dealing with a smaller set of results, then you can run the more computationally intensive clauses (especially those technical indicators that use exponential moving averages in their calculation) at the end of the scan.
For more information on defining your scan universe, please see our Support Center article on Planning Scans.
While slow-running scans can usually be fixed by putting the existing clauses in a different order, scans that return too few or too many results often need changes made to the clauses themselves.
The number of scan results returned can be anything from zero to 2000. If there are more than 2000 results, the scan engine will only show the first 2000. You want to have a manageable number of results to look at individually; typically 20-50 results is a good number to aim for. When your scan returns zero results or 2000+, that is often a sign that your scan syntax needs to be fixed.
If you are not getting a manageable number of results, there are several troubleshooting steps you can take to find and resolve the issue. Your approach will depend on whether you are getting too many or too few results. We've listed a few of the most helpful troubleshooting techniques below.
If you are getting too many results, check for OR clauses that are not appropriately grouped together with square brackets. This is a common source of problems with scans. Unless the clauses affected by the OR operator are surrounded with an additional set of square brackets, unexpected results may occur.
Clauses added with the AND operator are required criteria that all have to be met. Clauses added with the OR operator are a little different - they are part of a list of criteria, of which a security only has to meet one. Unfortunately, it isn't always clear to the scan engine exactly which clauses are part of the list, so you may not get the scan results you intended.
Here is an example:
[close > 20] and [country is US] or [country is Canada]
The intent seems to be to find any US or Canadian stock above $20. In this case, the list of criteria for the OR clause consists of these two clauses: “country is US”, “country is Canada”.
In reality, however, the scan engine will find all US stocks above $20 as well as ANY Canadian stock. It perceives the list of criteria as these two items: “close above 20 and country is US” plus “country is Canada.”
By surrounding the clauses on the list with an additional set of square brackets, we make it clear to the scan engine that the first clause is not part of the list:
[close > 20] and [[country is US] or [country is Canada]]
With these extra brackets, the scan will return any US or Canadian stock above $20, as intended.
As you can see, misplaced or missing brackets can radically alter the results. If the scan uses an OR operator, it is best to always add brackets around your list of clauses so you get what you expect.
If you are getting too few scan results, the first step is to figure out which clause might be causing the problem. The best way to do this is to pare down the scan to something very basic that does get scan results, then add clauses back in one at a time, checking the results at every step. Repeat this process until the results are not what you would expect. Consider the following scan, which does not return any results:
[type = stock] and [daily sma(20,daily volume) > 40000] and [Upper BB (20,2) < close] and [%B (20,2) < 0] and [close > 12]
Start by commenting out all clauses except the first one. This tells the scan engine to ignore those clauses. You can comment out a clause by adding two forward slashes at the beginning of that line of the scan:
[type = stock] //and [daily sma(20,daily volume) > 40000] //and [Upper BB (20,2) < close] //and [%B (20,2) < 0] //and [close > 12]
When you run the scan above, you will get the first 2000 stocks ([type = stock]) in the database. Uncomment the next line and run it again:
[type = stock] and [daily sma(20,daily volume) > 40000] //and [Upper BB (20,2) < close] //and [%B (20,2) < 0] //and [close > 12]
We still get 2000+ results, this time made up of stocks averaging at least 40,000 in volume, so we uncomment the next line and run the scan again. Eventually, we uncomment the %B clause. When we run the scan that time, we get zero scan results. This tells us that the %B clause is the likely culprit, allowing us to focus our troubleshooting efforts on that clause.
There could be a number of possible issues with this clause (or any other clause that gets zero results):
In our scan example above, the problem is a contradictory clause. The %B clause, as written, requires the closing price to be below the lower Bollinger band, but the Upper BB clause says that the price is above the upper Bollinger band. No stocks can be both above the upper and below the lower band at the same time. In this case, perhaps we meant for %B to be greater than zero. If we make this change and run the scan again, we will likely get results.
If the above troubleshooting techniques do not resolve the problem, it could be a scan design issue. Perhaps your criteria are too specific and you're getting too few results; or perhaps your criteria are not specific enough and you're getting too many results.
Take an inventory of the clauses in your scan. How many clauses are defining your universe? How many are defining the technical setup you want for the stocks? How many are crossover or other signal clauses in your scan?
If you have many signal clauses, this could be a problem: the odds are low that so many crossover events will all happen to a stock on the same day. On the opposite end of the spectrum, you will likely get too many results if you have no signal clauses at all.
Similarly, if you are narrowing down your universe too much or not enough, or if you have too few or too many technical condition clauses in your scan, you may not be getting the number of results you want. It takes a little bit of trial and error to find the right balance of universe definition, conditions and signals. Review our Support Center article on Planning Scans for more info.
Sometimes, when trying to debug a scan, we get far too many hits as we broaden our scope to find the problem. We can reduce this clutter in our test results by temporarily adding a “Starts With” clause to our scan. The example below limits our results to symbols that start with the letter A:
and [symbol starts with 'A']
Furthermore, if you are looking to see if a specific symbol is present in the scan results, you can change the clause to limit your results to just that specific symbol:
and [symbol = 'AAPL']
The clause above will only show Apple in the scan results. In some cases, looking at a single stock and its chart can help us discover errors in the scan logic. It can also help confirm the logic. If you expect a specific stock to be in the results, you can narrow the focus to just include that stock. Then proceed to add clauses and notice when the results change. This is easier than having to look at a large list of results to see if the stock is there.
Remember to remove the “Starts With” clause when you are done debugging.
As discussed in the previous section, one way to check the logic of a scan you're developing is to find a symbol that meets the scan criteria and see whether or not it shows up in the scan results.
However, just because your symbol doesn't appear in the scan results doesn't necessarily mean that there's anything wrong with your scan. It may just mean that the symbol is not in our scan engine.
An easy way to check this is to run a scan with just one clause:
[symbol = 'XYZ']
If symbol XYZ is returned as a scan result when you run this short scan, then the symbol is available in the scan engine, which means there might be something else wrong with the scan you are developing.
If this single-clause scan returns no results, that means symbol XYZ is not in our scan engine, which is why it didn't show up in the results for the scan you are developing.
It can be more difficult to troubleshoot the scan results when your scan uses a date offset. This is because the price, volume, etc. shown on the scan results page reflect today's values, not the values for the offset date.
In this situation, it can be helpful to create a chart that coincides with the offset date of the scan, so you can quickly verify the price, volume and indicator values for the correct date.
This can be done by choosing the “Select Start/End” option for the date range of the chart, then using the calendar popup to set the end date so that it matches your scan offset date. Adding the indicators you are interested in on the chart will display those indicator values as they existed on the requested date.
Note that the values in SharpCharts are typically rounded to two or three decimal places, whereas the Scan Engine is sensitive to values down to six decimal places.
Writing scans is more art than science, so it may take some of experimenting to get your scan working just the way you want. Using the troubleshooting techniques in this article can help you improve your scan. If you're still struggling, we have many resources to help you become a scan-writing expert. Check out our Getting Help with Scans article in the Support Center for more details.