Portfolio Analysis in Python with QuantStats
Key Takeaways
QuantStats library is used for portfolio analysis in Python, demonstrating various algorithms and techniques for evaluating portfolio performance.
Full Transcript
Today, we're going to learn how to do professional portfolio analysis in Python using a package called QuantStats. Now, this video is going to be particularly interesting for those of you who are financial experts interested in a little bit of coding and data science. It is also interesting for data science professionals that want to learn a little bit about quantitative finance, but I need to mention that I am primarily here a technical expert, so I'm here to teach you guys the technical part of it, how to implement stuff, how to automate stuff. I want to present you the package and how to work with it. I'm not the kind of guy who explains to you all the ratios and all the interpretations. So, of course, I will provide some explanations here and there, but primarily this is focused on the implementation part, showing you how to use this package and what you can do with it. So, if you like this video, let me know by hitting the like button and subscribing, and now let us get right into it. >> [music] >> All right, so we're going to learn how to do professional portfolio analysis in Python today using a package called QuantStats. And this is the GitHub repository of this package. As you can see here, it says portfolio analytics for quants. And in this quick start introduction here, you can see what's possible with this package. Essentially, this package allows you to do a couple of things. First of all, it offers utilities for getting data, so you can download stock data, historical stock data using this package itself. You don't need to use YFinance for that. You also have statistics, so individual numbers like Sharpe ratio or Sortino ratio. You have plotting capabilities to generate visualizations like this one, so to create charts, and you have reporting capabilities, so to create easily full reports with all the different metrics and all the different plots by just running a single line of code. This is what this package is about. Now, let's not talk about this for too long. Let's open up a terminal and navigate to our working directory. I'm going to assume that you have Python installed already. Besides that, I'm not going to assume anything. So, if you have Python on your system and you want to install the package globally, you can just go and say pip or pip3, depending on your operating system. You can try both. Install and then you want to install the package quantstats. That's the package we're going to need today. And if you want to use a virtual environment, you can do that. Just go to a directory that you want to be working in. In my case, that's going to be my tutorial directory here. And now you can either start a virtual environment using Python's VN feature. If you don't know what this is, just use the global version. I don't want to confuse those of you who are not interested in the details. In my case here, just for the sake of simplicity, I'm going to use UV. If you don't know what UV is, if you don't care about UV, don't worry about this. You're not missing out on anything. I'm just going to initialize my own project here. And instead of pip install here, I have to say UV at. But basically, I'm doing the same thing. Uh I'm adding quantstats to this uh project here. And in addition to that, we're going to also install something else called Jupyter Lab. This is an interactive Python notebook environment. So, you just uh go ahead and say pip or pip three install Jupyter Lab like this. Or if you're using UV like me, you can say UV at Jupyter Lab. Everything else stays the same. So, this is just a different setup depending on what you want to use here. And now what you need to do is you need to start this Jupyter Lab instance. So, once you have it installed, you just say Jupyter and then Lab like this. This time with a white space, not just Jupyter Lab, but Jupyter space Lab. And if you're using UV like me, you say UV run Jupyter Lab. And from now on, there shouldn't be any differences. This will open in your browser a window that shows you uh this Jupyter Lab environment. I'm going to move this now to a different screen, so it doesn't interfere here with our coding. And basically, we can create here now an interactive Python notebook. Just a very brief explanation for those of you who have never worked with interactive Python notebooks. These are just Python environments here or Python files where we can run individual cells. Usually, a Python script just runs from top to bottom. Here we have individual cells, so I can create a equals 10. I can run this. Uh then I can say print A, so I have my different commands here. And then I can say in another cell down below A equals 20. I can go back up and just run this cell, so I don't have to run the full script from top to bottom. I can run individual cells, which is very useful if you're just learning about a package. Once you have something that you actually want to use like an automation script for creating a report, you want to write this as an actual script. If you just want to learn, you just use a Jupiter notebook like an interactive Python notebook uh to to explore the package, to study it. And we're going to start to do exactly that. We're going to say import quantstats as qs. And this is just a common alias. And with qs now we can do a bunch of different things. The first thing I want to show you is that we can load data. So I can say qs.utils. This is one submodule that we can use. And here we have a bunch of functions, but what I'm interested in is downloading returns. So I'm just going to say qs.utils.download_returns, and I need to provide a ticker symbol. So let's go with something like Apple. AAPL is the ticker symbol for Apple. And this will result now in a I think it's a data frame or a series. Let me just store this here. Let's say returns is equal to that. And if I say type returns, we will see that this is a series because it only has the index and the value. And this series shows us the returns in percent. So these are not the actual price values, these are returns. And working with this sort of data, of course, makes more sense because we're interested in performance, not in absolute values. So we're going to get the returns like this. We also want to compare this to a benchmark. So what I'm going to do is I'm going to also load the S&P 500 ETF data. So I'm going to say here benchmark is equal to qs.utils.download_returns, and for the ticker symbol here I'm going to provide SPY. And you can also go with the index directly. I think it's um this hat symbol and then GSPC. I think it should also work Uh but SPY is what I'm going to go here with and this is the benchmark. If I just print that, it's also a series with a percentage changes. And now with QuantStats, we can easily get various metrics and statistics. So I can go here and say qs.stats. This is now a different module and I can choose any metric. I can go with tab to get auto completion. You can see here I have a bunch of things to choose from. Let's go with a classic one, sharp. I want to have the sharp ratio of the returns. Basically adjusted for volatility. So we're not just considering the returns but also the returns in relation to the volatility. And here we got a sharp ratio of 0.62. So this is probably not the most optimal set of returns here because you want to have a sharp ratio. As far as I know, none of this is financial advice by the way because I'm just a programmer, data scientist, machine learning engineer but I'm not a financial expert. So don't consider any of this financial advice. But as far as I know, the sharp ratio should be anywhere between one or two. So that is, yeah, maybe not the most optimal ratio. Then let's go and say for example the cumulative annual return. So I can go and say not sharp, sorry, the CAGR. We're going to go and get that. This is basically 19% per year. Also we can take a look at things like the max drawdown. That basically means from a peak to the value, what's the largest move we have. And in this case, we have minus 81%. This basically means that at some point the stock was at a peak and from there it dropped 81 or 82% almost. This is crazy. And you can keep going like this. I'm not going to show all of that. I just want to show you the principle. You can just get all sorts of stats here. You can also get the Greeks. So that would be by providing returns and the benchmark and then you can get to dict. You can get the alpha and the beta. So how much it moves with the market and how much um excess uh market return we have. And yeah, basically the stats module allows you to get these metrics, to just get numbers and that's it. But of course, sometimes you want to have visualizations and this is also super easy with QuantStats. Just qs.plots is the module and you can again just use auto completion here to get the different things that you can plot. The simplest one would be earnings, so I can just go returns and this would plot the earnings over time. So you can see this is the stock price um in in relative terms here of Apple and I can now go and for example also get a snapshot, which would be multiple plots. So I would just get the most important summary here. We would see the cumulative return, we would see the drawdown. This basically means again, we have a peak, how much do we go down, then we go to the next peak, how much do we go down from there? So this shows you how worse or or how bad it can get uh or how bad it got in the past with this asset, with this portfolio. Then you can also see the daily returns here. So that is a good summary plot. If you're only interested in the drawdown plot, we can also plot this individually. So we get the underwater plot. This would be again qs.plots and then drawdown and returns. This would just give me the underwater plot here with a mean as well, with an average here. Also another interesting thing would be the heat map, so qs.plots and then the heat map. What was the exact name? I think it was monthly heat map. Returns. This shows you nicely for each month the return, so you can have an overview here. You can see where the very bad months are and where the very good months are. And another interesting thing is you can do Monte Carlo simulations. So all you have to do for that is you just say qs.plots and then Monte Carlo, you provide the returns. Now here one caveat is you should not go with the full length maybe, because that's a bit difficult uh to to work with. So, in this case I'm just going to go with tail 252. So, that's the rough number of trading days per year and that would give me a Monte Carlo simulation uh basically just reshuffling the last 252 days and um showing how the journey could have gotten. So, basically the red thing you see here is the actual uh movement and then you have here the confidence band which basically shows you uh what this asset could have or where this asset could have gone until it gets here again. So, this is more like an analysis for a worst-case scenario for tail risks. So, you can see if you would have survived this movement. That's That's how I interpret it, but again, if you're financial expert, correct me if I'm wrong. You can write it down in the comments. Also, what you can do is you can do the same thing with stats. So, you can say qs .stats. So, the previous module again, you can again provide Monte Carlo, you can provide the returns, and also from the returns you can get the stats. And this will give you just a dictionary with min, max, mean, median of the performance. And if you want to theoretically, you can also provide the keyword sims. This will allow you to determine how many simulations you want to run. So, 100 would be fewer dots and we can also go with something like 10. That would then even be less or I can go with something like 200 which would be more dots and more outliers. And then maybe we'll get to the most convenient feature which is reports. You can just craft full reports by just typing qs reports and then the format that you want to have it in, for example, HTML, and then you get a full report using the returns and the benchmark. So, we can go ahead, for example, and type qs reports and then .html. I can provide here the returns and I can provide the benchmark. Then also a title if I want to have some heading. So, I can say AAPL versus S&P 500. And then I just have to provide output and that would be for example report. html. So, I can just run this line of code and that creates a full report with all the important statistics and all the plots in one HTML file. So, that's the easiest thing that you can do if you just want to create a report. I can just open this now here. This is in Jupiter lab, but you can also open this as a website. You can also print this as a PDF if you want to and here you have now APL versus S&P 500 compounded. You can see here the periods, the the trading days here. You can uh see the key performance metrics. Everything, all the stuff that I don't understand because I'm not a financial professional. Some of the stuff I do understand, but you see all sorts of plots like cumulative returns versus benchmark. You can see that this massively outperform the S&P 500 over time. Um then however, you can look at the sharp ratio and it's actually not that that great if you adjust for the volatility. You have the same thing log scaled here. You have also uh end of year returns. You have distribution of the monthly returns. You have the cumulative sum of daily returns and all the different plots. Again, underwater plots. Again, the heat map. And also here the box plots diagram with the quantiles of the returns. If I may for a second, I would like to plug myself in as the sponsor of my own video. If you go to my website neuralnine.com, you will find a tab services and a tab tutoring. Here you can hire me for all sorts of stuff like data science, machine learning, web development. If you need help with something in a project, here you can book me for one-on-one tutoring. If you want me to teach you personally something that you don't understand. If you like my teaching style, on both pages at the bottom you can contact me via mail and also via LinkedIn. Just wanted to let you know about this. But also you can work with this on a more granular level. So, you can say for example QS reports Uh, actually let me copy this. I'm going to just paste this down here. Instead of saying HTML, you can say basic. And that basically gives you just a basic small uh report with some of the metrics and with just some of the plots, but you can also go and say full, then you will get the full thing, not as HTML, but in your notebook. So, that is also possible. You can do it like this. And also, you can separate uh metrics and plots, so you can go up here and instead of saying full, you can just say reports metrics. And in case you would just get the numbers, and if you say plots, you would just get the plots. And they of course take some time to generate, but you get the idea. So, then finally, let me show you some practical examples. How can we do portfolio analysis with this? How can we craft our own portfolio? For this, let me import pandas as pd here. We're going to define our portfolio in very simple terms. We're going to have a weight dictionary, so I'm going to call this portfolio_ weights. And that is going to just contain the tickers and the weight that they have. So, AAPL could be 20% of my portfolio, then I could say Nvidia would be 30% of my portfolio, then I could say Tesla would be 0.15% of my portfolio, and then maybe Microsoft would be what's the remaining thing we have? Uh 65, so let's go with 35. Actually, that's too much for Microsoft. Let's go with 20 again, and then let's go with 15 something else. Let's go with Meta 0.15. Now, these are the weights. We of course want to get the actual returns, so I'm going to say returns is equal to pd data frame. And this data frame will be the result of a dictionary comprehension. So, I'm going to say we're mapping the ticker to a list, and the list will be the returns. So, we're just going to go and say qsutils.download_returns, the functions we already know from before, ticker, and then for ticker in portfolio weights. So, we're going to iterate over the keys, which are Apple, Nvidia, Tesla, Microsoft, Meta. We're going to iterate over this, get the returns, and then map ticker to the returns. And important, at the end of the day, we want to drop the NA values. So, we only want to have valid returns. Now, then of course, we just have the returns per asset. We didn't use our weights yet. So, what we want to do is we actually want to multiply the returns by the weights. So, our portfolio will be the result of taking the returns, and we need to multiply them by the weights, and we can do that easily with Pandas. We don't have to do any fancy iterations. We just have to turn the portfolio weights into a series. So, Pandas series portfolio weights, and then the entire thing here will be enclosed in parentheses, and we're going to sum it up on the axis one, and we're going to rename this to be port- folio. So, I can actually run this, and we can see what this looks like, so we know what we're working with. That is now just the portfolio Uh these are just now the portfolio returns all taken together. So, we're not differentiating between the different assets. These are just um all these combined into one set of returns. And now, as a benchmark, again, we're going to say S&P 500 is equal to uh qs utils download returns, and that's going to be SPY again. We're going to rename that to S&P uh 500. Or actually, let's go with SP500. I'm not sure if this is going to produce any troubles otherwise with the column name. But that's that. So, we have the portfolio, we have the S&P 500. We can also take a look at that. And now, I can just go ahead again, qs reports html, and then I can just provide returns. Or actually, sorry, no, portfolio, because that's where we have the weights. So, portfolio, SP500, then output is portfolio report html, and then also we want to have a title. The title is going to be portfolio versus S&P 500. And here we can actually use the ampersand. So, that will create a report. And this report now looks actually not this one. This report here now looks like that. We have our strategy. Strategy means portfolio basically in this case. We can see the sharp ratio is a little bit better. Um or actually this is the S&P 500. The sharp ratio of our portfolio is actually uh pretty good. Probably because of Nvidia, I guess, because Nvidia has some very steep returns. And you can see now this is the entire portfolio analysis. Now, another thing that we can do is also vectorized backtesting. Uh this is not really a backtesting package, but you can do it. You can apply strategy in a vectorized way. So, we're not doing it step-by-step, but we're taking it just if this strategy produces a signal the day before, we're going to go long the next day. Very simple stuff, but I want to show you how to do that, too. For this we're going to install an additional package. This is just playing around, so you don't have to do this if you're not interested in backtesting, but we can go to our tutorial directory now and we can just say UV at in my case or you can say again globally pip or pip three install TA-Lib. This is just technical analysis lib, so uh actually sorry, like this. UV at TA-Lib. This is going to add it to my package. Otherwise, again pip pip three install TA-Lib. That is just so we can easily get the MACD because we're going to implement a very very simple MACD trading strategy. So, I'm going to say import TA-Lib as TA and then also import yfinance as yf because we need the price data and actually maybe I'm not sure if we need that. If this is not already part, maybe we also need to install uh yfinance. Let me see if it No, actually it's already part of it, so I think YFinance is already installed automatically with one of the other packages. And now we're just going to get the price data. We're going to calculate the MACD, the MACD signal, and everything. We're going to implement a very basic trading strategy. If a signal is produced or if our condition is met, we're going to go long the next day. So, we're going to go simple. We're going to say price is equal to YF ticker. Let's just take one asset, AAPL. We're going to get the historical data. Let's pick as a starting date here 2010. 1st of January, and we're only going to look at the close price. Then one thing we need to do is we need to make it not time zone aware, so price index is going to be equal to price index TZ localize, I think is the function. Um and we're going to say none. So, that would be now our price data. We have the price of the Apple uh stock. And now we can easily say MACD and something that we're not interested in is given the price data. So, now we have MACD like this. And essentially we're just going to say here that our position is going to be MACD greater than the signal. That's our condition. We're going to say shift, and the fill value is going to be equal to false. So, we can do that. And then we also want to have the return, so the daily return is going to be equal to price percentage change. We want to fill the non values or non values uh with zero. And then our strategy basically is we want to get the daily return if our condition was met the day before. So, this is again vectorized very, very simple. We're just doing this on a daily basis. If this condition was met the day before, we're going to go long this day, otherwise not. So, we just say basically our strategy, so our returns are going to be taking the daily return times position. So, one or zero depending on if the MACD was above the signal. And then, we can also rename this. So, take that and then rename this to be MACD. So, if we take a look that at this, this is also just going to be a series of returns. And compared to that, we also want to have buy and hold. That is just going to be the daily returns, and we're going to rename them to be buy and hold. So, that's just going to be our benchmark. Now, we're not going to use the S&P 500. We're using the same asset. One strategy is just doing the MACD condition here, and the other one is buy and hold. And we want to have a report that compares the two. So, QuantStats reports HTML HTML, and then we have the strategy. We have buy and hold as the benchmark. We have a title, which would be MACD versus buy hold, for example. Output would be macd.html. And now when I run this, we get a full report again with these two strategies compared. So, MACD HTML like this. And you can see that actually buy and hold would be the better choice here, that we actually don't make very good returns with the MACD. Sharp ratio for our strategy is better because it's less volatile. Uh so, yeah. You can analyze this again. So, this is how we can do professional portfolio analysis in Python using QuantStats. That's it for this video today. I hope you enjoyed it and hope you learned something. If so, let me know by hitting the like button and leave a comment in the comment section down below. Also, in case you're interested on my website, you will find a services tab and a tutoring tab. There you can contact me if you need help with a project, if you need guidance, if you need a freelancer, if you need a tutor. You can contact me at the bottom of these pages using LinkedIn or email. Besides that, don't forget to subscribe to this channel and hit the notification bell to not miss a single future video for free. Other than that, thank you very much for watching. See you in the next video and bye.
Original Description
💻️ Need some help with a project or some consulting? Contact me here: https://www.neuralnine.com/services
🐍 The Python Bible Book: https://www.neuralnine.com/books/
💻 The Algorithm Bible Book: https://www.neuralnine.com/books/
More on: Algorithm Basics
View skill →
🎓
Tutor Explanation
DeepCamp AI