Transcription
In a previous tutorial, we learned how to code this opening range breakout strategy with the interactive brokers API and the IB async library. Now, uh, one limitation to our approach in the last tutorial is that we just had a command line script here that accepted arguments. So, we just had to, uh, pass in the symbols that we wanted to trade for a given day. And we would just pass in stuff like Apple, Microsoft, Tesla, QQQ, very popular, uh, stock symbols to trade.
But what if you wanted to dynamically uh select which stocks uh to trade based on certain criteria? So some people like to trade what are called stocks in play when the market opens. You might want stocks that uh have higher volume than usual, stocks that have large gaps, uh stocks trading above a certain price, or maybe stocks that are above key moving averages.
In this tutorial, I'm going to show you how to build a market scanner so that you can scan for symbols in real time after the market opens and then pass those symbols over to your trading scripts for further uh price action monitoring and actual order placement. We're going to start off with a very simple scanner here that scans for high open gaps. And then we're going to gradually add complexity and some calculations here and add more filters until we have a more fine-tuned set of stocks that we want to trade.
And then once you've built several of these scanners, you'll start to see patterns emerge. And so one thing I've done is I have a scanner presets file here where I have a dictionary where I can just name this the scan I want to run. And then I just pass that over to my Python code and just say run a scan with this name. And so you'll see ones I have like pullback EMA 20 trend all EMAs uh leaders trend confirmed IV expansion most active volume rate heat short-term search etc. upcoming earnings Momo, quality Momo, and things like that. And so you can just group all these different tag values and filters together under a single key here. And then once you find certain scans you personally like to run, you can actually take one of these scanners and plug it into your trading script. So I had that opening range breakout script. And so what I did was add this fetch scanner symbols function in here. And I can just pass it a scan name and it'll run that scan name and then get those symbols dynamically, pass them to my trading scripts, and actually uh place the orders.
And so just an example of what you can end up with. I'm going to run this here. You'll see it's going to uh wait for the opening range and scanned all the different symbols, detect the breakouts. And so I'm not sure if you heard that, but there was an actual order placed. And so for my particular conditions here, it found Arista Networks and today is August 6. And so that's what came up here. And I believe there was one more. Uh so if you look at my orders here, I have uh Astera Labs and whatever L EU is right there.
So, if you want to follow along at home, I have a full write up and all of the source code available for free on my website at hackingthemarkets.com. Also, link below. Full disclosure, I have a link to Interactive Brokers. If you decide to check them out, there's more information that supports the channel and all the time I spent putting this together. So, let's go ahead and get started with the tutorial.
So, before we can get all fancy and combine multiple sophisticated scanners with trading scripts and monitoring price action and so forth, we need to start off very simple. And so if you're watching this channel, I assume you have some interest in Python for trading and that you already know how to set up a Python environment. So um I recommend you have at least Python 3.10. So something a little more modern that came out in the last four years. Not all these packages are going to work forever on your old Python 3.5 or whatever you might be running. So make sure you're up to date. Uh secondly, you need to have a trader workstation or IB gateway. We're going to be running this in paper trading mode so that we can test all this out without risking any capital. And so make sure you have an interactive brokerage account and uh trader workstation or IB gateway. If you don't have an account, as I mentioned, I do have a link where you can uh sign up that supports the channel. And so assuming you have all that set up, you'll be able to run the code that I will be discussing here.
And so the first thing we're going to do is build a simple scanner with just a single scan code uh no filters. And to run this, you need to actually have the IBA async package that I talked about in my last video. So, I will stop this script and make sure you uh pip install IBA async and make sure you have a a recent version of Python. I'm running 3.12. Um I think some older versions of Python won't actually support IBA async. So, make sure you're up to date.
And so, in the first example, what we're doing is creating just a basic scanner with no uh special filters or anything like that. just a single uh scan code. And so to do that, I need to first connect to interactive brokers and then create this an instance of the scanner subscription object. So to do that, I first have to import the classes from the IBA async package. Then I connect to my trader workstation. So I have this running in paper trading mode right here. And so my trader workstation uh is already running. I have it running on 7497. That's the paper trading port. And I give it a client client ID in case I want to run multiple uh clients. I can have different client IDs for each one of them.
And so once I'm connected to my Trader Workstation, I need to instantiate a new scanner subscription. And that requires a few different parameters. Uh the main thing we need here is a scan code. And there's a huge list of scan codes that I'll go over uh towards the end of the video, but I'm selecting one called high open gap. And I'm specifying that I want to scan for stocks on the major exchanges. So I have an instrument of stock and I'm doing a location code of stock US major right there. And so you might be trading other types of instruments like options or futures. In this case, I'm trading stocks and looking for stocks that have gapped up the highest.
Now, once I have the scanner subscription object uh created, I just need to pass that over to request scanner data to retrieve uh the data for that particular scanner subscription. And then I'm returning that into scan data. And then once I have that scan data, I can iterate over it. And so let's go ahead and print what that looks like just uh without iterating iterating over it. So if I run this, you'll see that I have this big list of scan data right here. And so that's in a list. And so I can't really read that cuz it's all globed together. And so what I do is loop over those results one by one. And then I can just uh print the data as it comes in and then select the different attributes that I want to print out. So let's just print out the data just like that. And so when I print each of these out, you see they're all scan data objects and they all have a rank and a certain contract associated with them. And so all I'm really interested in now is, you know, just the rank and the symbol. So I just want to print those out. So for each of those scan data objects, uh let's just go ahead and print out the uh scan data rank and the contract details symbol. So that's kind of nested inside of contract details. I can get down to the contract and the symbol.
And so when I run this, what you're going to see is client ID is already in use. Retry with unique client ID and it says is client ID one uh already in use. And yes, it is actually because what I did off the screen a second ago is run this uh web app here that I'm going to use to pull up some of the charts. And so recently I built this uh and I haven't made a tutorial on this yet, but I'll probably get to it, but I made this fast API app that will serve up uh charts of all these. That way when I do these scans, I can show you the charts of what's going on. So, I have this little real-time chart uh trading view widget here that I've hooked up to Interactive Brokers. And then I also have this market scanner. So, when we learn how to build these scanners, I'm going to show you how to build a web version of this uh at some point in the future when I put put it together. So, you can select different scan types, show them on the web, and then drill down and see the real-time chart loaded on Trading View. And I also have this thing with trading logs so that you can monitor what's going on with your trades. But I'm not going to do that quite yet, but I'm going to use this app real quick um on this video. So um so let me stop that. And also this is a good example of client ID. So what I can do is run uh I'll just run my web app on a different uh client ID here. And I should be able to run that web app and connect. And then I'm going to run this scanner on client ID 1. And you see my scan comes back. And you'll see I have a variety of symbols coming back.
Now, a lot of these symbols that gapped up highly are probably these small smaller stocks. And what we're going to do is add filters uh to these so that we can get larger, more liquid stocks. And so, uh, just an example of what came up here. Let's look at these last couple uh LYW. And so, I can go to my uh real-time chart guy here and then type that in. And you'll see LYW. Uh this looks like it had a large gap down. And so this would be if you hook this up to opening range breakout, it would actually go uh short right there. And then so let's look at AIMD. Uh that one looks like it came up in my other unusual volume scan right here. A IMD. And so if I go to my real-time chart here, or I can click it from here, I'll see uh AIMD right there. And so that looks to have uh possibly gapped up but then faded out. And so I don't know what this stock is, but it's something I would expect there to be some type of news on. Yeah. you see it went up 31% and so I'm expecting they had earnings or some a big big deal. So A IMD news uh they secured a $2 million order for a deployment of AI nose and semiconductor manufacturing. So you know a lot of AI stocks we mentioned earlier uh looks like AET Arista Networks uh popped up recently. So if you look at those AET Arista Networks and uh Aster right I think those might have reported earnings recently. So the AI stocks obviously everyone's hearing about that. So that's what's hot right now and those come up in a lot of these scans. U and so yeah that's the most uh basic scans scanning for these high opening gaps.
And so you can see there's two weaknesses here in that um one uh this is pulling up a bunch of stocks that I've never heard of. So they probably gapped up a lot but they're like small small cap stocks. Maybe you want to trade those, maybe you don't. That's not for me to tell you. Um, but um, I want to filter this down to stocks that are a little bit larger, have a little bit higher volume, and so I'm going to add some filters. The second weakness I have here is that um, you see I had to pull up all these charts to see how much these stocks gapped up. So here I just have a scanner uh, for the symbols, but I didn't have any detail about the price or what yesterday's close was or today's open, and so I couldn't calculate that percent. So let's add on to the script. Let's take what we learned in the previous videos where we fetch historical data and combine that with our stock scanner.
And so in this script, you'll see what I have is a scanner subscription just like the one we just ran. But as we're looping through the scan data, we're getting the contract object itself and then we're passing it over to this function called calculate gap percentage. And so my script here, I have a calculate gap percentage function that's going to take our interactive brokers connection and the contract object. And for each contract, we're going to request historical data so that we get the historical bars. We're going to get uh yesterday's data and today's. So today's will be the last bar in the list. So the negative first index in the list of bars. And then the previous bar before that, which would be yesterday, is the negative2 bar. So the second from the last, right? And then all we need to do is take today's open and look at yesterday's close and figure out the percentage and return it back to our script. And then we can print that out along with our rank. And then all we need to do is run this and we'll get our gap percentage with each one of our stocks. And we'll get the stocks in ranked order here along with the percentage each of them gapped up. So you'll see the highest open gaps are actually over 100% here. And then the the 10th ranked one here is 26%.
Now I'm going to run that one more time. You're going to see how each of them come back one by one just like that. Now I think that's pretty fast and fast enough here. But in our last uh tutorial, we did one on uh asynchronous programming. And so I've went ahead and included an asynchronous version on here that actually uses co- routines here. And then you'll see I use async gather to run a lot of these in parallel. So instead of sequentially, what we can do is run this asynchronous version and then run those in parallel. And you'll see it comes back a little bit quicker, right? And so one takes like 7 seconds and this one takes like 2 or 3 seconds. It runs a little bit quicker, but for 10 symbols, it's not really that much of a difference. However, if you want to run as quick as possible, you can run this asynchronously, and I've included the code right there. I'm not going to do a whole another tutorial on asynchronous programming cuz I already did that in the first video of the opening range breakout series.
So, now we have a simple scanner that's able to return the stock symbols that gapped up the most. And we have the ability to fetch historical data for each of those symbols so that we can perform any calculations we want on the price data, including how much each stock gapped up in percentage terms. Now, we might want to filter down that symbol list, though. So, pretend we don't want to trade any of these small cap stocks, and we want stocks that are above a certain market cap, stocks that are above a certain price. We don't want penny stocks. We want stocks that are above $10 a share, and we want stocks that have a certain uh amount of volume. And so to do that, we need to add these tag values and filters. And so to do that, we're going to need to import this class called tag value. And we're going to instantiate that to build a list of filters. So each filter we want, we want to add it to this list of filters and then pass it to our request scanner data function.
And so in this particular case, I have a tag value of market cap above a certain amount. And this amount is in millions. And so if I want uh stocks that are above 10 billion in market cap, I would do$10,000 right there. I want stocks that are above uh $10 a share. And so USD price above, I'm doing $10 here. And then we want might want volume above a million shares. And there's a dollar volume uh amount that you can also use as a filter. And so I have three filters here in a list. And so I just have a list called filters. And then there are in instances of a tag value. This is actually a named tpple actually. So it's a a named tpple called tag value. And it just has two values, the uh filter name and then the uh filter value right there. And so once we built that list, we pass it over to request scanner data. And then we can return that right back. And you'll see instead of these particular stocks uh coming back, we'll get some larger cap uh stocks that we've actually probably heard of before.
And so I'm going to run my uh filter price and volume script right here. And if I run that, let's see what symbols we get. Now you'll see uh we get Ster Labs and Arista Networks as we mentioned previously, but we also have uh Shopify and Unity. And so if we look at uh Shopify in our web app here, uh we can see uh what Shopify did. You see uh it gapped up and ran as well. Um I assume they reported earnings. I'm not sure. And then what else do I have? I have uh Unity, which I think gap down. and I saw that one today. And so, uh, it gapped down and then you see it, uh, trended down throughout the day. And so, I'm not here to tell you exactly what stocks to trade. I just know it's generally a good idea to filter down to more, uh, liquid stocks. And you can do that by adding these, uh, scanner subscription filters that are just a list of these tag value, uh, tpples that you can pass in. And that's just one example.
And so, let's say we want to filter this list down even more based on current market conditions. And so, uh, we just made a scanner that found stocks that are above $10 billion in market cap that are above $10 a share. Um, and these are just stocks that gapped up the most that meet those conditions. But you notice some of these kind of faded off after the gap up. Let's say we want to filter this and find stocks that not only gapped up, but also continued to trend higher throughout the day. And so, let's add what's called a gap go filter. And let's say we we find stocks that gapped up and then went up by a certain percentage after the market opened. And so here I just add another filter called change open percent above three. And so I want stocks that gapped up highly and then went up at least another 3% after that. And so this will filter that down even more.
What I also have here is another historical data request. You see I have calculate since open percentage. And so what I'll do here is use our historical data requests to look at the open of today and then the highest of the current day so far. And then with that historical data for just the current day, we can see which stocks went up the most after the open. And so I'm going to run this real quick. So filter gap and go. All right. And so you see Astera Labs there uh went up 6% after the open. So 20% gap up and then after the open it's still up 6% post the open. The maximum run during that time is 11%. Uh likewise uh with Shopify. Um Apple there is kind of interesting because it didn't gap up very much at all. Right. It's very small gap but you see this one's run after the open. For whatever reason Apple is up uh 5.6% right now. And oh actually you can see the news here. Apple to announce a hundred billion dollars in US investment uh following Trump iPhone. I don't know what's going on there.
Now in my function called calculate since open percentage here you'll see I have a request historical data request but it's for one minute data cuz it's calculating intraday statistics. So now we have two historical data requests. So we have the uh the daily time frame to calculate the opening gap percent based on uh yesterday's close and then we have an intraday which is the current mark market data and we're looking at the 1 minute bars here and seeing how much the stock has run up since the open so that we can show this statistic right here.
Now while I've been doing this you may have been wondering how did you know to write market cap above 1 e to 6 or change open purse above like how do you know the names of all these tag values? Well, surely in the Interactive Brokers documentation, these are all listed out nicely and explained for us to use, but actually they're not. If you look in the documentation, it says you should call a function called request scanner parameters in order to get the list dynamically. And so that's what I've done here. And that uh that uh scanner parameters function actually returns all of this information as XML. And which is not really ideal. We have we don't really deal with XML much these days. If you worked in the 2000s, maybe a little in the 2010s, then you worked with XML. So, it's a little it seems a little bit outdated.
And so, to handle that, what I've done is create a little I vibe coded a little uh a dumper here that will take uh that the results of that request, parse the XML, and then dump all those scan codes to a file. And so, this I didn't even bother uh writing this cuz it was very tedious. And so, I used some AI generated code right here. And that will just make the request scanner parameters function call. It will find all the different scan types in that XML using like uh uh what is it? XQuery. And then it will dump all those and with along with all of their descriptions. And so I've included that uh script here. And so I'll run that real quick called dump scanner parameters. And so you can see what that looks like. And so it dumps all these different types. So you see there's 648 types of scans and 747 filter fields. And I have those dumping to a directory called IBKR scanner parameters. And so you can see a complete list as a CSV. And so here are all the various uh filter fields. So you can see ones like uh Moody's ratings, open, gap, percent, above. And that's where I got all these. And so there's a short description, you know, analyst ratings, earnings, a bunch of different uh I think there's fundamental uh factors, uh ETF values, uh whether they're optionable, dividends, and so forth. And then there's some scan types like we use with top open percent gain, top price range, and trade rate.
And so, um, what I did was find all the different, uh, scan codes and filters that were of interest to me. And since all these scanners follow a common pattern, I built my own little scanner library called a scanner presets here. And I've been putting this together with some different sets of scans that can run. And so, I just took all these values and and once you have them, you can just give them a name in a dictionary. And then I have this little set of presets that I can run. And so, let's say I want to run all of my uh various scans. I can run them, right? And so I'm running like 20 different scans here that find the top five symbols that match my particular uh scans right there and then returning them. And then you can decide whether to pipe those into a uh trading script. So you can see uh these scans are a little bit complicated to get set up initially, but once you uh put them all together, um you can make something very powerful to find the exact selection of stocks you want in real time uh for trading candidates and hook them up to your uh scripts that actually place orders.
And so that's it for now. I'm going to be doing some traveling soon. So uh I might not post for a while, but um hopefully before I go, I'll post something related to um building this web app. So, I'm going to do this real-time trading dashboard where I hook up uh Trading View Lightweight charts in JavaScript to a web application. I'm going to use fast API and server events for real-time data. I'm going to show a web- based uh market scanner here and then a trade log. And I'm going to incorporate Trading View web hooks since a lot of people have been asking me about that. So, that's for now. I'll see you in the next video. Bye.