Writing scans does not always go as hoped, and the more complex the scan, the more likely something unintended will occur. 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 how quickly the scan runs. These two symptoms indicate very different underlying problems, and are 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; it just gets 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. So, it filters 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 just checks to see if the stock is one of the 500 stocks in the S&P 500. Processing a computational clause like ”[Chande Trend Meter > 80.0]”, on the other hand, calls for some intensive number crunching, which takes 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, and limits your scan results to 500 stocks right away. Then the more intensive Chande Trend Meter clause only has to be run against 500 stocks. Even though it takes a comparatively long time per stock, you are 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, by using 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 999. If there are more than 999 results, the scan engine will just show you the first 999. 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 999+, 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, and you just have to meet one of the criteria on the list. 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 may be to find any US or Canadian stock above $20. In that 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 sees the list of criteria as these two items: “close above 20 and country is US”, “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 the scan down to something very basic that does get scan results, and then add clauses back in one at a time, checking the scan 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 999 stocks ([type = stock]) in the database. Now 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 999+ results, this time 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, and when we run the scan that time, we get zero scan results. This tells us that the %B clause is the likely culprit, and we can 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. Either your criteria are too specific and you're getting too few results; or your criteria are not specific enough, and you are 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. This one limits our results to symbols that start with the letter A:
and [symbol starts with 'A']
Further, 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 it doesn't appear in the scan results, that 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, and 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, and that's 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, and 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, and it may take a little bit 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.