Technology has become an asset in finance: financial institutions are now evolving to technology companies rather than just staying occupied with just the financial aspect: besides the fact that technology brings about innovation the speeds and can help to gain a competitive advantage, the speed and frequency of financial transactions, together with the large data volumes, makes that financial institutions’ attention for technology has increased over the years and that technology has indeed become a main enabler in finance.

Among the hottest programming languages for finance, you’ll find R and Python, alongside languages such as C++, C# and Java. In this tutorial, you’ll learn how to get started with Python for finance. The tutorial will cover the following:

Download the Jupyter notebook of this tutorial here.

## Getting Started With Python for Finance

Before you go into trading strategies, it’s a good idea to get the hang of the basics first. This first part of the tutorial will focus on explaining the Python basics that you need to get started. This does not mean, however, that you’ll start completely from zero: you should have at least done DataCamp’s free Intro to Python for Data Science course, in which you learned how to work with Python lists, packages, and NumPy. Additionally, it is desired to already know the basics of Pandas, the well-known Python data manipulation package, but this is no requirement.

If you want to apply your new 'Python for Data Science' skills to real-world financial data, consider taking the Importing and Managing Financial Data in Python course.

When a company wants to grow and undertake new projects or expand, it can issue stocks to raise capital. A stock represents a share in the ownership of a company and is issued in return for money. Stocks are bought and sold: buyers and sellers trade existing, previously issued shares. The price at which stocks are sold can move independent of the company’s success: the prices instead reflect supply and demand. This means that, whenever a stock is considered as ‘desirable’, due to a success, popularity, … the stock price will go up.

**Note** that stocks are not exactly the same as bonds, which is when companies raise money through borrowing, either as a loan from a bank or by issuing debt.

As you just read, buying and selling or trading is essential when you’re talking about stocks, but certainly not limited to it: trading is the act of buying or selling *an asset*, which could be financial security, like stock, a bond or a tangible product, such as gold or oil.

Stock trading is then the process of the cash that is paid for the stocks is converted into a share in the ownership of a company, which can be converted back to cash by selling, and this all hopefully with a profit. Now, to achieve a profitable return, you either go long or short in markets: you either by shares thinking that the stock price will go up to sell at a higher price in the future, or you sell your stock, expecting that you can buy it back at a lower price and realize a profit. When you follow a fixed plan to go long or short in markets, you have a trading strategy.

Developing a trading strategy is something that goes through a couple of phases, just like when you, for example, build machine learning models: you formulate a strategy and specify it in a form that you can test on your computer, you do some preliminary testing or backtesting, you optimize your strategy and lastly, you evaluate the performance and robustness of your strategy.

Trading strategies are usually verified by backtesting: you reconstruct, with historical data, trades that would have occurred in the past using the rules that are defined with the strategy that you have developed. This way, you can get an idea of the effectiveness of your strategy and you can use it as a starting point to optimize and improve your strategy before applying it to real markets. Of course, this all relies heavily on the underlying theory or belief that any strategy that has worked out well in the past will likely also work out well in the future, and, that any strategy that has performed poorly in the past will likely also do badly in the future.

A time series is a sequence of numerical data points taken at successive equally spaced points in time. In investing, a time series tracks the movement of the chosen data points, such as the stock price, over a specified period of time with data points recorded at regular intervals. If you’re still in doubt about what this would exactly look like, take a look at the following example:

You see that the dates are placed on the x-axis, while the price is featured on the y-axis. The “successive equally spaced points in time” in this case means that the days that are featured on the x-axis are 14 days apart: note the difference between 3/7/2005 and the next point, 3/31/2005, and 4/5/2005 and 4/19/2005.

However, what you’ll often see when you’re working with stock data is not just two columns, that contain period and price observations, but most of the times, you’ll have five columns that contain observations of the period and the opening, high, low and closing prices of that period. This means that, if your period is set at a daily level, the observations for that day will give you an idea of the opening and closing price for that day and the extreme high and low price movement for a particular stock during that day.

For now, you have a basic idea of the basic concepts that you need to know to go through this tutorial. These concepts will come back soon enough and you’ll learn more about them later on in this tutorial.

Getting your workspace ready to go is an easy job: you basically just make sure you have Python and an Integrated Development Environment (IDE) running on your system. However, there are some ways in which you can get started that are maybe a little easier when you’re just starting out.

Take for instance Anaconda, a high performance distribution of Python and R and includes over 100 of the most popular Python, R and Scala packages for data science. Additionally, installing Anaconda will give you access to over 720 packages that can easily be installed with conda, our renowned package, dependency and environment manager, that is included in Anaconda. And, besides all that, you’ll get the Jupyter Notebook and Spyder IDE with it.

That sounds like a good deal, right?

You can install Anaconda from here and don’t forget to check out how to set up your Jupyter Notebook in DataCamp’s Jupyter Notebook Tutorial: The Definitive Guide.

Of course, Anaconda is not your only option: you can also check out the Canopy Python distribution (which doesn’t come free), or try out the Quant Platform.

The latter offers you a couple additional advantages over using, for example, Jupyter or the Spyder IDE, since it provides you everything you need specifically to do financial analytics in your browser! With the Quant Platform, you’ll gain access to GUI-based Financial Engineering, interactive and Python-based financial analytics and your own Python-based analytics library. What’s more, you’ll also have access to a forum where you can discuss solutions or questions with peers!

When you’re using Python for finance, you’ll often find yourself using the data manipulation package, Pandas. But also other packages such as NumPy, SciPy, Matplotlib,… will pass by once you start digging deeper.

For now, let’s just focus on Pandas and using it to analyze time series data. This section will explain how you can import data, explore and manipulate it with Pandas. On top of all of that, you’ll learn how you can perform common financial analyses on the data that you imported.

The `pandas-datareader`

package allows for reading in data from sources such as Google, Yahoo! Finance, World Bank,… If you want to have an updated list of the data sources that are made available with this function, go to the documentation. For this tutorial, you will use the package to read in data from Yahoo! Finance. Make sure to install the package first by installing the latest release version via pip with `pip install pandas-datareader`

.

**Tip**: if you want to install the latest development version or if you experience any issues, you can read up on the installation instructions here.

`import pandas_datareader as pdr import datetime aapl = pdr.get_data_yahoo('AAPL', start=datetime.datetime(2006, 10, 1), end=datetime.datetime(2012, 1, 1))`

**Note** that the Yahoo API endpoint has recently changed and that, if you want to already start working with the library on your own, you’ll need to install a temporary fix until the patch has been merged into the master brach to start pulling in data from Yahoo! Finance with `pandas-datareader`

. Make sure to read up on the issue here before you start on your own!

No worries, though, for this tutorial, the data has been loaded in for you so that you don’t face any issues while learning about finance in Python with Pandas.

It’s wise to consider though that, even though `pandas-datareader`

offers a lot of options to pull in data into Python, it isn’t the only package that you can use to pull in financial data: you can also make use of libraries such as Quandl, for example, to get data from Google Finance:

`import quandl aapl = quandl.get("WIKI/AAPL", start_date="2006-10-01", end_date="2012-01-01")`

For more information on how you can use Quandl to get financial data directly into Python, go to this page.

Lastly, if you’ve already been working in finance for a while, you’ll probably know that you most often use Excel also to manipulate your data. In such cases, you should know that you can integrate Python with Excel.

Check out DataCamp’s Python Excel Tutorial: The Definitive Guide for more information.

The first thing that you want to do when you finally have the data in your workspace is getting your hands dirty. However, now that you’re working with time series data, this might not seem as straightforward, since your index now contains DateTime values.

No worries, though! Let’s start step-by-step and explore the data first with some functions that you’ll might already know if you have some prior programming experience with R or if you’ve already worked with Pandas.

Either way, you’ll see it’s very easy!

As you saw in the code chunk above, you have used `pandas_datareader`

to import data into your workspace. The resulting object `aapl`

is a DataFrame, which is a 2-dimensional labeled data structure with columns of potentially different types. Now, one of the first things that you probably do when you have a regular DataFrame on your hands, is running the `head()`

and `tail()`

functions to take a peek at the first and the last rows of your DataFrame. Luckily, this doesn’t change when you’re working with time series data!

**Tip**: also make sure to use the `describe()`

function to get some useful summary statistics about your data.

Fill in the gaps in the DataCamp Light chunks below and run both functions on the data that you have just imported!

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIFJldHVybiBmaXJzdCByb3dzIG9mIGBhYXBsYFxuYWFwbC5fX19fKClcblxuIyBSZXR1cm4gbGFzdCByb3dzIG9mIGBhYXBsYFxuYWFwbC5fX19fKClcblxuIyBEZXNjcmliZSBgYWFwbGBcbmFhcGwuX19fX19fXygpIiwic29sdXRpb24iOiIjIFJldHVybiBmaXJzdCByb3dzIG9mIGBhYXBsYFxuYWFwbC5oZWFkKClcblxuIyBSZXR1cm4gbGFzdCByb3dzIG9mIGBhYXBsYFxuYWFwbC50YWlsKClcblxuIyBEZXNjcmliZSBgYWFwbGBcbmFhcGwuZGVzY3JpYmUoKSIsInNjdCI6IkV4KCkudGVzdF9mdW5jdGlvbihcImFhcGwuaGVhZFwiKVxuRXgoKS50ZXN0X2Z1bmN0aW9uKFwiYWFwbC50YWlsXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJhYXBsLmRlc2NyaWJlXCIpXG5zdWNjZXNzX21zZyhcIkdyZWF0IGpvYiEgTm93IHVzZSB0aGUgSVB5dGhvbiBjb25zb2xlIHRvIHByaW50IHRoZSByZXN1bHRzIG9mIHRoZSBgaGVhZCgpYCwgYHRhaWwoKWAgYW5kIGBkZXNjcmliZSgpYCBmdW5jdGlvbnMuXCIpIn0=

As you have seen in the introduction, this data clearly contains the four columns with the opening and closing price per day and the extreme high and low price movements for the Apple stock for each day. Additionally, you also get two extra columns: `Volume`

and `Adj Close`

.

The former column is used to register the number of shares that got traded during a single day. The latter, on the other hand, is the adjusted closing price: it’s the closing price of the day that has been slightly adjusted to include any actions that occurred at any time before the next day’s open. You can use this column to examine historical returns or when you’re performing a detailed analysis on historical returns.

Note how the index or row labels contain dates, and how your columns or column labels contain numerical values.

**Tip**: if you now would like to save this data to a csv file with the `to_csv()`

function from `pandas`

and that you can use the `read_csv()`

function to read the data back into Python. This is extremely handy in cases where, for example, the Yahoo API endpoint has changed and you don’t have access to your data any longer :)

`import pandas as pd aapl.to_csv('data/aapl_ohlc.csv') df = pd.read_csv('data/aapl_ohlc.csv', header=0, index_col='Date', parse_dates=True)`

Now that you have briefly inspected the first lines of your data and have taken a look at some summary statistics, it’s time to go a little bit deeper.

One way to do this is by inspecting the index and the columns and by selecting, for example, the last ten rows of a certain column. The latter is called subsetting because you take a small subset of your data. The result of the subsetting is a Series, which is a one-dimensional labeled array that is capable of holding any type.

**Remember** that the DataFrame structure was a two-dimensional labeled array with columns that potentially hold different types of data.

Check all of this out in the exercise below. First, use the `index`

and `columns`

attributes to take a look at the index and columns of your data. Next, subset the `Close`

column by only selecting the last 10 observations of the DataFrame. Make use of the square brackets `[]`

to isolate the last ten values. You might already know this way of subsetting from other programming languages, such as R. To conclude, assign the latter to a variable `ts`

and then check what type `ts`

is by using the `type()`

function:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEluc3BlY3QgdGhlIGluZGV4IFxuYWFwbC5fX19fX1xuXG4jIEluc3BlY3QgdGhlIGNvbHVtbnNcbmFhcGwuX19fX19fX1xuXG4jIFNlbGVjdCBvbmx5IHRoZSBsYXN0IDEwIG9ic2VydmF0aW9ucyBvZiBgQ2xvc2VgXG50cyA9IF9fX19bJ0Nsb3NlJ11bLTEwOl1cblxuIyBDaGVjayB0aGUgdHlwZSBvZiBgdHNgIFxudHlwZShfXykiLCJzb2x1dGlvbiI6IiMgSW5zcGVjdCB0aGUgaW5kZXggXG5hYXBsLmluZGV4XG5cbiMgSW5zcGVjdCB0aGUgY29sdW1uc1xuYWFwbC5jb2x1bW5zXG5cbiMgU2VsZWN0IG9ubHkgdGhlIGxhc3QgMTAgb2JzZXJ2YXRpb25zIG9mIGBDbG9zZWBcbnRzID0gYWFwbFsnQ2xvc2UnXVstMTA6XVxuXG4jIENoZWNrIHRoZSB0eXBlIG9mIGB0c2AgXG50eXBlKHRzKSIsInNjdCI6IkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYWFwbC5pbmRleFwiLCBub3RfdHlwZWRfbXNnPVwiRGlkIHlvdSBmb3JnZXQgdG8gYWNjZXNzIHRoZSBgaW5kZXhgIG9mIGBhYXBsYD9cIilcbkV4KCkudGVzdF9zdHVkZW50X3R5cGVkKFwiYWFwbC5jb2x1bW5zXCIsIG5vdF90eXBlZF9tc2c9XCJEaWQgeW91IGZvcmdldCB0byBhY2Nlc3MgdGhlIGBjb2x1bW5zYCBvZiBgYWFwbGA/XCIpXG5FeCgpLmNoZWNrX29iamVjdChcInRzXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJ0eXBlXCIpXG5zdWNjZXNzX21zZyhcIkF3ZXNvbWUhIE1ha2Ugc3VyZSB0byB1c2UgdGhlIElQeXRob24gY29uc29sZSB0byBwcmludCBvdXQgdGhlIHJlc3VsdCBvZiwgZm9yIGV4YW1wbGUsIGBhYXBsLmluZGV4YCEgSXQncyB2ZXJ5IGltcG9ydGFudCB0byBleHBsb3JlIHlvdXIgZGF0YSBwcm9wZXJseS5cIikifQ==

The square brackets can be nice to subset your data, but they are maybe not the most idiomatic way to do things with Pandas. That’s why you should also take a look at the `loc()`

and `iloc()`

functions: you use the former for label-based indexing and the latter for positional indexing.

In practice, this means that you can pass the label of the row labels, such as `2007`

and `2006-11-01`

, to the `loc()`

function, while you pass integers such as `22`

and `43`

to the `iloc()`

function.

Complete the exercise below to understand how both `loc()`

and `iloc()`

work:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEluc3BlY3QgdGhlIGZpcnN0IHJvd3Mgb2YgTm92ZW1iZXItRGVjZW1iZXIgMjAwNlxucHJpbnQoYWFwbC5sb2NbcGQuVGltZXN0YW1wKCcyMDA2LTExLTAxJyk6cGQuVGltZXN0YW1wKCcyMDA2LTEyLTMxJyldLl9fX19fXylcblxuIyBJbnNwZWN0IHRoZSBmaXJzdCByb3dzIG9mIDIwMDcgXG5wcmludChhYXBsLmxvY1snMjAwNyddLl9fX19fXylcblxuIyBJbnNwZWN0IE5vdmVtYmVyIDIwMDZcbnByaW50KGFhcGwuX19fX1syMjo0M10pXG5cbiMgSW5zcGVjdCB0aGUgJ09wZW4nIGFuZCAnQ2xvc2UnIHZhbHVlcyBhdCAyMDA2LTExLTAxIGFuZCAyMDA2LTEyLTAxXG5wcmludChhYXBsLmlsb2NbWzIyLDQzXSwgWzAsIDNdXSkiLCJzb2x1dGlvbiI6IiMgSW5zcGVjdCB0aGUgZmlyc3Qgcm93cyBvZiBOb3ZlbWJlci1EZWNlbWJlciAyMDA2XG5wcmludChhYXBsLmxvY1twZC5UaW1lc3RhbXAoJzIwMDYtMTEtMDEnKTpwZC5UaW1lc3RhbXAoJzIwMDYtMTItMzEnKV0uaGVhZCgpKVxuXG4jIEluc3BlY3QgdGhlIGZpcnN0IHJvd3Mgb2YgMjAwNyBcbnByaW50KGFhcGwubG9jWycyMDA3J10uaGVhZCgpKVxuXG4jIEluc3BlY3QgTm92ZW1iZXIgMjAwNlxucHJpbnQoYWFwbC5pbG9jWzIyOjQzXSlcblxuIyBJbnNwZWN0IHRoZSAnT3BlbicgYW5kICdDbG9zZScgdmFsdWVzIGF0IDIwMDYtMTEtMDEgYW5kIDIwMDYtMTItMDFcbnByaW50KGFhcGwuaWxvY1tbMjIsNDNdLCBbMCwgM11dKSIsInNjdCI6IkV4KCkudGVzdF9mdW5jdGlvbihcInByaW50XCIsIGluZGV4PTEsIGluY29ycmVjdF9tc2c9XCJEaWQgeW91IGFkZCBgaGVhZCgpYCB0byBpbnNwZWN0IHRoZSBmaXJzdCByb3dzIG9mIE5vdmVtYmVyLURlY2VtYmVyIDIwMDY/XCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJwcmludFwiLCBpbmRleD0yLCBpbmNvcnJlY3RfbXNnPVwiRGlkIHlvdSBhZGQgYGhlYWQoKWAgdG8gaW5zcGVjdCB0aGUgZmlyc3Qgcm93cyBvZiAyMDA3P1wiKVxuRXgoKS50ZXN0X2Z1bmN0aW9uKFwicHJpbnRcIiwgaW5kZXg9MywgaW5jb3JyZWN0X21zZz1cIkRpZCB5b3UgdXNlIGBpbG9jYCB0byBpbnNwZWN0IE5vdmVtYmVyIDIwMDY/IFJlbWVtYmVyIHRoYXQgeW91IHVzZSBgaWxvY2AgZm9yIHBvc2l0aW9uYWwgaW5kZXhpbmdcIilcbkV4KCkudGVzdF9mdW5jdGlvbihcInByaW50XCIsIGluZGV4PTQsIGluY29ycmVjdF9tc2c9XCJEaWQgeW91IHJlbW92ZSBzb21ldGhpbmcgZnJvbSB0aGUgb3JpZ2luYWwgY29kZT9cIilcbnN1Y2Nlc3NfbXNnKFwiV2VsbCBkb25lISBJbmRleGluZyBpcyBhIGRpZmZpY3VsdCBwYXJ0IG9mIFBhbmRhcyBhbmQgeW91J3ZlIG9idmlvdXNseSBtYXN0ZXJlZCB0aGUgYmFzaWNzIVwiKSJ9

**Tip**: if you look closely at the results of the subsetting, you’ll notice that there are certain days missing in the data; If you look more closely at the pattern, you’ll see that it’s usually two or three days that are missing; These days are usually weekend days or public holidays and aren’t part of your data. This is nothing to worry about: it’s completely normal and you don’t have to fill in these missing days.

Besides indexing, you might also want to explore some other techniques to get to know your data a little bit better. You never know what else will show up. Let’s try to sample some 20 rows from the data set and then let’s resample the data so that `aapl`

is now at the monthly level instead of daily. You can make use of the `sample()`

and `resample()`

functions to do this:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIFNhbXBsZSAyMCByb3dzXG5zYW1wbGUgPSBhYXBsLl9fX19fXygyMClcblxuIyBQcmludCBgc2FtcGxlYFxucHJpbnQoX19fX19fKVxuXG4jIFJlc2FtcGxlIHRvIG1vbnRobHkgbGV2ZWwgXG5tb250aGx5X2FhcGwgPSBhYXBsLl9fX19fX19fKCdNJykubWVhbigpXG5cbiMgUHJpbnQgYG1vbnRobHlfYWFwbGBcbnByaW50KF9fX19fX19fX19fXykiLCJzb2x1dGlvbiI6IiMgU2FtcGxlIDIwIHJvd3NcbnNhbXBsZSA9IGFhcGwuc2FtcGxlKDIwKVxuXG4jIFByaW50IGBzYW1wbGVgXG5wcmludChzYW1wbGUpXG5cbiMgUmVzYW1wbGUgdG8gbW9udGhseSBsZXZlbCBcbm1vbnRobHlfYWFwbCA9IGFhcGwucmVzYW1wbGUoJ00nKS5tZWFuKClcblxuIyBQcmludCBgbW9udGhseV9hYXBsYFxucHJpbnQobW9udGhseV9hYXBsKSIsInNjdCI6IkV4KCkudGVzdF9vYmplY3QoXCJzYW1wbGVcIilcbkV4KCkudGVzdF9mdW5jdGlvbihcInByaW50XCIsIGluZGV4PTEpXG5FeCgpLnRlc3Rfb2JqZWN0KFwibW9udGhseV9hYXBsXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJwcmludFwiLCBpbmRleD0yKVxuc3VjY2Vzc19tc2coXCJHb29kIGpvYiEgWW91IGhhdmUgc3VjY2Vzc2Z1bGx5IHNhbXBsZWQgYW5kIHJlc2FtcGxlZCB5b3VyIGRhdGEhXCIpIn0=

Very straightforward, isn’t it?

The `resample()`

function is often used because it provides elaborate control and more flexibility on the frequency conversion of your times series: besides specifying new time intervals yourself and specifying how you want to handle missing data, you also have the option to indicate how you want to resample your data, as you can see in the code example above. This stands in clear contract to the `asfreq()`

method, where you only have the first two options.

**Tip**: try this out for yourself in the IPython console of the above DataCamp Light chunk. Pass in `aapl.asfreq("M", method="bfill")`

to see what happens!

Lastly, before you take your data exploration to the next level and start with visualizing your data and performing some common financial analyses on your data, you might already start to calculate the differences between the opening and closing prices per day. You can easily perform this arithmetic operation with the help of Pandas; Just substract the values in the `Open`

column of your `aapl`

data from the values of the `Close`

column of that same data. Or, in other words, subtract `aapl.Close`

from `aapl.Open`

. You storethe result in a new column of the `aapl`

DataFrame called `diff`

and then you delete it again with the help of `del`

:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEFkZCBhIGNvbHVtbiBgZGlmZmAgdG8gYGFhcGxgIFxuYWFwbFsnZGlmZiddID0gYWFwbC5PcGVuIC0gYWFwbC5DbG9zZVxuXG4jIERlbGV0ZSB0aGUgbmV3IGBkaWZmYCBjb2x1bW5cbmRlbCBhYXBsWydkaWZmJ10ifQ==

**Tip**: make sure to comment out the last line of code so that the new column of your `aapl`

DataFrame doesn’t get removed and you can check the results of your arithmetic operation!

Of course, knowing the gains in absolute terms might already help you to get an idea of whether you’re making a good investment, but as a quant, you might be more interested in a more relative means of measuring your stock’s value, like how much the value of a certain stock has gone up or gone down. A way to do this is by calculating the daily percentage change.

This is good to know for now, but don’t worry about it just yet; You’ll go deeper into this in a bit!

This section introduced you to some ways to first explore your data before you start performing some prior analyses. However, you can still go a lot further in this; Consider taking our Python Exploratory Data Analysis if you want to know more.

Next to exploring your data by means of `head()`

, `tail()`

, indexing, … You might also want to visualize your time series data. Thanks to Pandas’ plotting integration with Matplotlib, this task becomes easy; Just use the `plot()`

function and pass the relevant arguments to it. Additionally, you can also add the `grid`

argument to indicate that the plot should also have a grid in the background.

Let’s examine and run the code below to see how you can make this plot!

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEltcG9ydCBNYXRwbG90bGliJ3MgYHB5cGxvdGAgbW9kdWxlIGFzIGBwbHRgXG5pbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0XG5cbiMgUGxvdCB0aGUgY2xvc2luZyBwcmljZXMgZm9yIGBhYXBsYFxuYWFwbFsnQ2xvc2UnXS5wbG90KGdyaWQ9VHJ1ZSlcblxuIyBTaG93IHRoZSBwbG90XG5wbHQuc2hvdygpIn0=

If you want to know more about Matplotlib and how to get started with it, check out DataCamp’s Intermediate Python for Data Science course.

## Common Financial Analysis

Now that you have an idea of your data, what time series data is about and how you can use `pandas`

to quickly explore your data, it’s time to dive deeper into some of the common financial analyses that you can do so that you can actually start working towards developing a trading strategy.

In the rest of this section, you’ll learn more about the returns, moving windows, volatility calculation and Ordinary Least-Squares Regression (OLS).

The simple **daily percentage change** doesn’t take into account dividends and other factors and represents the amount of percentage change in the value of a stock over a single day of trading. You will find that the daily percentage change is easily calculated, as there is a `pct_change()`

function included in the Pandas package to make your life easier:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEltcG9ydCBgbnVtcHlgIGFzIGBucGBcbmltcG9ydCBudW1weSBhcyBucFxuXG4jIEFzc2lnbiBgQWRqIENsb3NlYCB0byBgZGFpbHlfY2xvc2VgXG5kYWlseV9jbG9zZSA9IGFhcGxbWydfX19fX19fX19fXyddXVxuXG4jIERhaWx5IHJldHVybnNcbmRhaWx5X3BjdF9jaGFuZ2UgPSBkYWlseV9jbG9zZS5fX19fX19fX19fKClcblxuIyBSZXBsYWNlIE5BIHZhbHVlcyB3aXRoIDBcbmRhaWx5X3BjdF9jaGFuZ2UuZmlsbG5hKDAsIGlucGxhY2U9VHJ1ZSlcblxuIyBJbnNwZWN0IGRhaWx5IHJldHVybnNcbnByaW50KF9fX19fX19fX19fX19fKVxuXG4jIERhaWx5IGxvZyByZXR1cm5zXG5kYWlseV9sb2dfcmV0dXJucyA9IG5wLmxvZyhkYWlseV9jbG9zZS5wY3RfY2hhbmdlKCkrMSlcblxuIyBQcmludCBkYWlseSBsb2cgcmV0dXJuc1xucHJpbnQoZGFpbHlfbG9nX3JldHVybnMpIiwic29sdXRpb24iOiIjIEltcG9ydCBgbnVtcHlgIGFzIGBucGBcbmltcG9ydCBudW1weSBhcyBucFxuXG4jIEFzc2lnbiBgQWRqIENsb3NlYCB0byBgZGFpbHlfY2xvc2VgXG5kYWlseV9jbG9zZSA9IGFhcGxbWydBZGogQ2xvc2UnXV1cblxuIyBEYWlseSByZXR1cm5zXG5kYWlseV9wY3RfY2hhbmdlID0gZGFpbHlfY2xvc2UucGN0X2NoYW5nZSgpXG5cbiMgUmVwbGFjZSBOQSB2YWx1ZXMgd2l0aCAwXG5kYWlseV9wY3RfY2hhbmdlLmZpbGxuYSgwLCBpbnBsYWNlPVRydWUpXG5cbiMgSW5zcGVjdCBkYWlseSByZXR1cm5zXG5wcmludChkYWlseV9wY3RfY2hhbmdlKVxuXG4jIERhaWx5IGxvZyByZXR1cm5zXG5kYWlseV9sb2dfcmV0dXJucyA9IG5wLmxvZyhkYWlseV9jbG9zZS5wY3RfY2hhbmdlKCkrMSlcblxuIyBQcmludCBkYWlseSBsb2cgcmV0dXJuc1xucHJpbnQoZGFpbHlfbG9nX3JldHVybnMpIiwic2N0IjoiRXgoKS50ZXN0X2ltcG9ydChcIm51bXB5XCIpXG5FeCgpLnRlc3Rfb2JqZWN0KFwiZGFpbHlfY2xvc2VcIilcbkV4KCkudGVzdF9vYmplY3QoXCJkYWlseV9wY3RfY2hhbmdlXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJwcmludFwiLCBpbmRleD0xKVxuRXgoKS50ZXN0X29iamVjdChcImRhaWx5X2xvZ19yZXR1cm5zXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJwcmludFwiLCBpbmRleD0yKVxuc3VjY2Vzc19tc2coXCJDb25ncmF0dWxhdGlvbnMhIFlvdSBoYXZlIHN1Y2Nlc3NmdWxseSBjYWxjdWxhdGVkIHRoZSBkYWlseSBwZXJjZW50YWdlIGNoYW5nZSFcIikifQ==

Note that you calculate the log returns to get a better insight into the growth of your returns over time.

Knowing how to calculate the daily percentage change is nice, but what when you want to know the monthly or quarterly returns? In such cases, you can fall back on the `resample()`

, which you already saw in the first part of this tutorial.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlID0gYWFwbFtbJ0FkaiBDbG9zZSddXVxuZGFpbHlfcGN0X2MgPSBkYWlseV9jbG9zZS5wY3RfY2hhbmdlKCkiLCJzYW1wbGUiOiIjIFJlc2FtcGxlIGBhYXBsYCB0byBidXNpbmVzcyBtb250aHMsIHRha2UgbGFzdCBvYnNlcnZhdGlvbiBhcyB2YWx1ZSBcbm1vbnRobHkgPSBhYXBsLl9fX19fX19fXygnQk0nKS5hcHBseShsYW1iZGEgeDogeFstMV0pXG5cbiMgQ2FsY3VsYXRlIHRoZSBtb250aGx5IHBlcmNlbnRhZ2UgY2hhbmdlXG5tb250aGx5LnBjdF9jaGFuZ2UoKVxuXG4jIFJlc2FtcGxlIGBhYXBsYCB0byBxdWFydGVycywgdGFrZSB0aGUgbWVhbiBhcyB2YWx1ZSBwZXIgcXVhcnRlclxucXVhcnRlciA9IGFhcGwucmVzYW1wbGUoXCI0TVwiKS5tZWFuKClcblxuIyBDYWxjdWxhdGUgdGhlIHF1YXJ0ZXJseSBwZXJjZW50YWdlIGNoYW5nZVxucXVhcnRlci5fX19fX19fX19fKCkiLCJzb2x1dGlvbiI6IiMgUmVzYW1wbGUgYGFhcGxgIHRvIGJ1c2luZXNzIG1vbnRocywgdGFrZSBsYXN0IG9ic2VydmF0aW9uIGFzIHZhbHVlIFxubW9udGhseSA9IGFhcGwucmVzYW1wbGUoJ0JNJykuYXBwbHkobGFtYmRhIHg6IHhbLTFdKVxuXG4jIENhbGN1bGF0ZSB0aGUgbW9udGhseSBwZXJjZW50YWdlIGNoYW5nZVxubW9udGhseS5wY3RfY2hhbmdlKClcblxuIyBSZXNhbXBsZSBgYWFwbGAgdG8gcXVhcnRlcnMsIHRha2UgdGhlIG1lYW4gYXMgdmFsdWUgcGVyIHF1YXJ0ZXJcbnF1YXJ0ZXIgPSBhYXBsLnJlc2FtcGxlKFwiNE1cIikubWVhbigpXG5cbiMgQ2FsY3VsYXRlIHRoZSBxdWFydGVybHkgcGVyY2VudGFnZSBjaGFuZ2VcbnF1YXJ0ZXIucGN0X2NoYW5nZSgpIiwic2N0IjoiRXgoKS50ZXN0X29iamVjdChcIm1vbnRobHlcIilcbkV4KCkudGVzdF9mdW5jdGlvbihcIm1vbnRobHkucGN0X2NoYW5nZVwiKVxuRXgoKS50ZXN0X29iamVjdChcInF1YXJ0ZXJcIilcbkV4KCkudGVzdF9mdW5jdGlvbihcInF1YXJ0ZXIucGN0X2NoYW5nZVwiKVxuc3VjY2Vzc19tc2coXCJXZWxsIGRvbmUhXCIpIn0=

Using `pct_change()`

is quite the convenience, but it also obscures how exactly the daily percentages are calculated. That’s why you can alternatively make use of Pandas’ `shift()`

function instead of using `pct_change()`

. You then divide the `daily_close`

values by the `daily_close.shift(1) -1`

. By using this function, however, you will be left with `NA`

values in the beginning of the resulting DataFrame.

**Tip**: compare the result of the following code with the result that you had obtained in the first DataCamp Light chunk to clearly see the difference between these two methods of calculating the daily percentage change.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlID0gYWFwbFtbJ0FkaiBDbG9zZSddXSIsInNhbXBsZSI6IiMgRGFpbHkgcmV0dXJuc1xuZGFpbHlfcGN0X2NoYW5nZSA9IF9fX19fX19fX19fIC8gZGFpbHlfY2xvc2Uuc2hpZnQoMSkgLSAxXG5cbiMgUHJpbnQgYGRhaWx5X3BjdF9jaGFuZ2VgXG5wcmludChfX19fX19fX19fXykiLCJzb2x1dGlvbiI6IiMgRGFpbHkgcmV0dXJuc1xuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlIC8gZGFpbHlfY2xvc2Uuc2hpZnQoMSkgLSAxXG5cbiMgUHJpbnQgYGRhaWx5X3BjdF9jaGFuZ2VgXG5wcmludChkYWlseV9wY3RfY2hhbmdlKSIsInNjdCI6IkV4KCkudGVzdF9vYmplY3QoXCJkYWlseV9wY3RfY2hhbmdlXCIpXG5FeCgpLnRlc3RfZnVuY3Rpb24oXCJwcmludFwiKVxuc3VjY2Vzc19tc2coXCJBd2Vzb21lIGpvYiEgWW91IHNlZSwgdGhlcmUgYXJlIG1hbnkgd2F5cyB0byBjb21lIHRvIHlvdXIgZGFpbHkgcGVyY2VudGFnZSBjaGFuZ2UhXCIpIn0=

**Tip**: calculate the daily log returns with the help of Pandas’ `shift()`

function. Try it out in the IPython console of this DataCamp Light chunk! (For those who can’t find the *solution*, try out this line of code: `daily_log_returns_shift = np.log(daily_close / daily_close.shift(1))`

).

For your reference, the calculation of the daily percentage change is based on the following formula: \(r_t = \dfrac{{p_t}}{p_{t-1}} - 1\), where *p* is the price, *t* is the time (a day in this case) and *r* is the return.

Additionally, you can plot the distribution of `daily_pct_change`

:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlID0gYWFwbFtbJ0FkaiBDbG9zZSddXVxuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlLnBjdF9jaGFuZ2UoKVxuZGFpbHlfcGN0X2NoYW5nZS5maWxsbmEoMCwgaW5wbGFjZT1UcnVlKSIsInNhbXBsZSI6IiMgSW1wb3J0IG1hdHBsb3RsaWJcbmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHRcblxuIyBQbG90IHRoZSBkaXN0cmlidXRpb24gb2YgYGRhaWx5X3BjdF9jYFxuZGFpbHlfcGN0X2NoYW5nZS5oaXN0KGJpbnM9NTApXG5cbiMgU2hvdyB0aGUgcGxvdFxucGx0LnNob3coKVxuXG4jIFB1bGwgdXAgc3VtbWFyeSBzdGF0aXN0aWNzXG5wcmludChkYWlseV9wY3RfY2hhbmdlLmRlc2NyaWJlKCkpIn0=

The distribution looks very symmetrical and normally distributed: the daily changes center around the bin 0.00. Note, though, how you can and should use the results of the `describe()`

function, applied on `daily_pct_c`

, to correctly interpret the results of the histogram. You will see that the mean is very close to the 0.00 bin also and that the standard deviation is 0.02. Also take a look at the percentiles to know how many of your data points fall below -0.010672, 0.001677 and 0.014306.

The **cumulative daily rate of return** is useful to determine the value of an investment at regular intervals. You can calculate the cumulative daily rate of return by using the daily percentage change values, adding `1`

to them and calculating the cumulative product with the resulting values:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlX3B4ID0gYWFwbFtbJ0FkaiBDbG9zZSddXVxuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlX3B4LnBjdF9jaGFuZ2UoKVxuZGFpbHlfcGN0X2NoYW5nZS5maWxsbmEoMCwgaW5wbGFjZT1UcnVlKSIsInNhbXBsZSI6IiMgQ2FsY3VsYXRlIHRoZSBjdW11bGF0aXZlIGRhaWx5IHJldHVybnNcbmN1bV9kYWlseV9yZXR1cm4gPSAoMSArIF9fX19fX19fX19fX19fX18pLmN1bXByb2QoKVxuXG4jIFByaW50IGBjdW1fZGFpbHlfcmV0dXJuYFxucHJpbnQoX19fX19fX19fX19fX19fX18pIiwic29sdXRpb24iOiIjIENhbGN1bGF0ZSB0aGUgY3VtdWxhdGl2ZSBkYWlseSByZXR1cm5zXG5jdW1fZGFpbHlfcmV0dXJuID0gKDEgKyBkYWlseV9wY3RfY2hhbmdlKS5jdW1wcm9kKClcblxuIyBQcmludCBgY3VtX2RhaWx5X3JldHVybmBcbnByaW50KGN1bV9kYWlseV9yZXR1cm4pIiwic2N0IjoiRXgoKS50ZXN0X29iamVjdChcImN1bV9kYWlseV9yZXR1cm5cIilcbkV4KCkudGVzdF9mdW5jdGlvbihcInByaW50XCIpXG5zdWNjZXNzX21zZyhcIkF3ZXNvbWUhXCIpIn0=

Note that you can use can again use Matplotlib to quickly plot the `cum_daily_return`

; Just add the `plot()`

function to it and, optionally, determine the `figsize`

or the size of the figure:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlX3B4ID0gYWFwbFtbJ0FkaiBDbG9zZSddXVxuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlX3B4LnBjdF9jaGFuZ2UoKVxuZGFpbHlfcGN0X2NoYW5nZS5maWxsbmEoMCwgaW5wbGFjZT1UcnVlKVxuY3VtX2RhaWx5X3JldHVybiA9ICgxICsgZGFpbHlfcGN0X2NoYW5nZSkuY3VtcHJvZCgpIiwic2FtcGxlIjoiIyBJbXBvcnQgbWF0cGxvdGxpYlxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdCBcblxuIyBQbG90IHRoZSBjdW11bGF0aXZlIGRhaWx5IHJldHVybnNcbmN1bV9kYWlseV9yZXR1cm4ucGxvdChmaWdzaXplPSgxMiw4KSlcblxuIyBTaG93IHRoZSBwbG90XG5wbHQuc2hvdygpIn0=

Very easy, isn’t it? Now, if you don’t want to see the daily returns, but rather the monthly returns, remmeber that you can easily use the `resample()`

function to bring the `cum_daily_return`

to the monthly level:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmRhaWx5X2Nsb3NlX3B4ID0gYWFwbFtbJ0FkaiBDbG9zZSddXVxuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlX3B4LnBjdF9jaGFuZ2UoKVxuZGFpbHlfcGN0X2NoYW5nZS5maWxsbmEoMCwgaW5wbGFjZT1UcnVlKVxuY3VtX2RhaWx5X3JldHVybiA9ICgxICsgZGFpbHlfcGN0X2NoYW5nZSkuY3VtcHJvZCgpIiwic2FtcGxlIjoiIyBSZXNhbXBsZSB0aGUgY3VtdWxhdGl2ZSBkYWlseSByZXR1cm4gdG8gY3VtdWxhdGl2ZSBtb250aGx5IHJldHVybiBcbmN1bV9tb250aGx5X3JldHVybiA9IGN1bV9kYWlseV9yZXR1cm4uX19fX19fX18oXCJNXCIpLm1lYW4oKVxuXG4jIFByaW50IHRoZSBgY3VtX21vbnRobHlfcmV0dXJuYFxucHJpbnQoX19fX19fX19fX19fX19fX18pIiwic29sdXRpb24iOiIjIFJlc2FtcGxlIHRoZSBjdW11bGF0aXZlIGRhaWx5IHJldHVybiB0byBjdW11bGF0aXZlIG1vbnRobHkgcmV0dXJuIFxuY3VtX21vbnRobHlfcmV0dXJuID0gY3VtX2RhaWx5X3JldHVybi5yZXNhbXBsZShcIk1cIikubWVhbigpXG5cbiMgUHJpbnQgdGhlIGBjdW1fbW9udGhseV9yZXR1cm5gXG5wcmludChjdW1fbW9udGhseV9yZXR1cm4pIiwic2N0IjoiRXgoKS50ZXN0X29iamVjdChcImN1bV9tb250aGx5X3JldHVyblwiKVxuRXgoKS50ZXN0X2Z1bmN0aW9uKFwicHJpbnRcIilcbnN1Y2Nlc3NfbXNnKFwiU3VjY2VzcyEgVGhlIGByZXNhbXBsZSgpYCBmdW5jdGlvbiBjbGVhcmx5IGNvbWVzIGluIHZlcnkgaGFuZHkhXCIpIn0=

Knowing how to calculate the returns is a valuable skill, but you’ll often see that these numbers don’t really say much when you don’t compare them to other stock. That’s why you’ll often see examples where two or more stocks are compared. In the rest of this section, you’ll focus on getting more data from Yahoo! Finance so that you can calculate the daily percentage change and compare the results.

**Note** that, if you want to be doing this, you’ll need to have a more thorough understanding of Pandas and how you can manipulate your data with Pandas!

Let’s start! Get more data from Yahoo! Finance first. You can easily do this by making a function that takes in the `ticker`

or symbol of the stock, a start date and an end date. The next function that you see, `data()`

, then takes the `ticker`

to get your data from the `startdate`

to the `enddate`

and returns it so that the `get()`

function can continue. You map the data with the right `tickers`

and return a DataFrame that concatenates the mapped data with tickers.

Check out the code below, where the stock data from Apple, Microsoft, IBM, and Google are loaded and gathered into one big DataFrame:

`def get(tickers, startdate, enddate): def data(ticker): return (pdr.get_data_yahoo(ticker, start=startdate, end=enddate)) datas = map (data, tickers) return(pd.concat(datas, keys=tickers, names=['Ticker', 'Date'])) tickers = ['AAPL', 'MSFT', 'IBM', 'GOOG'] all_data = get(tickers, datetime.datetime(2006, 10, 1), datetime.datetime(2012, 1, 1))`

**Note** that this code orignally was used in “Mastering Pandas for Finance”. It was updated for this tutorial to the new standards. Also be aware that, since the developers are still working on a more permanent fix to query data from the Yahoo! Finance API, it could be that you need to import the `fix_yahoo_finance`

package. You can find the installation instructions here or check out the Jupyter notebook that goes along with this tutorial.

For the rest of this tutorial, you’re safe, as the data has been loaded in for you!

Now, the result of these lines of code, you ask? Check it out:

You can then use the big DataFrame to start making some interesting plots:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWxsX2RhdGEgPSBwZC5yZWFkX2NzdihcImh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9hc3NldHMuZGF0YWNhbXAuY29tL2Jsb2dfYXNzZXRzL2FsbF9zdG9ja19kYXRhLmNzdlwiLCBpbmRleF9jb2w9IFswLDFdLCBoZWFkZXI9MCwgcGFyc2VfZGF0ZXM9WzFdKSIsInNhbXBsZSI6IiMgSW1wb3J0IG1hdHBsb3RsaWJcbmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQgXG5cbiMgSXNvbGF0ZSB0aGUgYEFkaiBDbG9zZWAgdmFsdWVzIGFuZCB0cmFuc2Zvcm0gdGhlIERhdGFGcmFtZVxuZGFpbHlfY2xvc2VfcHggPSBhbGxfZGF0YVtbJ0FkaiBDbG9zZSddXS5yZXNldF9pbmRleCgpLnBpdm90KCdEYXRlJywgJ1RpY2tlcicsICdBZGogQ2xvc2UnKVxuXG4jIENhbGN1bGF0ZSB0aGUgZGFpbHkgcGVyY2VudGFnZSBjaGFuZ2UgZm9yIGBkYWlseV9jbG9zZV9weGBcbmRhaWx5X3BjdF9jaGFuZ2UgPSBkYWlseV9jbG9zZV9weC5wY3RfY2hhbmdlKClcblxuIyBQbG90IHRoZSBkaXN0cmlidXRpb25zXG5kYWlseV9wY3RfY2hhbmdlLmhpc3QoYmlucz01MCwgc2hhcmV4PVRydWUsIGZpZ3NpemU9KDEyLDgpKVxuXG4jIFNob3cgdGhlIHJlc3VsdGluZyBwbG90XG5wbHQuc2hvdygpIn0=

Another useful plot is the scatter matrix. You can easily do this by using the `pandas`

library. Don’t forget to add the `scatter_matrix()`

function to your code so that you actually make a scatter matrix :) As arguments, you pass the `daily_pct_change`

and as a diagonal, you set that you want to have a Kernel Density Estimate (KDE) plot. Additionally, you can set the transparency with the `alpha`

argument and the figure size with `figsize`

.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWxsX2RhdGEgPSBwZC5yZWFkX2NzdihcImh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9hc3NldHMuZGF0YWNhbXAuY29tL2Jsb2dfYXNzZXRzL2FsbF9zdG9ja19kYXRhLmNzdlwiLCBpbmRleF9jb2w9IFswLDFdLCBoZWFkZXI9MCwgcGFyc2VfZGF0ZXM9WzFdKVxuZGFpbHlfY2xvc2VfcHggPSBhbGxfZGF0YVtbJ0FkaiBDbG9zZSddXS5yZXNldF9pbmRleCgpLnBpdm90KCdEYXRlJywgJ1RpY2tlcicsICdBZGogQ2xvc2UnKVxuZGFpbHlfcGN0X2NoYW5nZSA9IGRhaWx5X2Nsb3NlX3B4LnBjdF9jaGFuZ2UoKSIsInNhbXBsZSI6IiMgSW1wb3J0IG1hdHBsb3RsaWJcbmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHRcblxuIyBQbG90IGEgc2NhdHRlciBtYXRyaXggd2l0aCB0aGUgYGRhaWx5X3BjdF9jaGFuZ2VgIGRhdGEgXG5wZC5zY2F0dGVyX21hdHJpeChkYWlseV9wY3RfY2hhbmdlLCBkaWFnb25hbD0na2RlJywgYWxwaGE9MC4xLGZpZ3NpemU9KDEyLDEyKSlcblxuIyBTaG93IHRoZSBwbG90XG5wbHQuc2hvdygpIn0=

**Note** that you might need to use the `plotting`

module to make the scatter matrix (i.e. `pd.plotting.scatter_matrix()`

) when you’re working locally. Also, it’s good to know that the Kernel Density Estimate plot estimates the probability density function of a random variable.

Congratulations! You’ve successfully made it through the first common financial analysis, where you explored returns! Now it’s time to move on to the second one, which are the moving windows.

Moving windows are there when you compute the statistic on a window of data represented by a particular period of time and then slide the window across the data by a specified interval. That way, the statistic is continually calculated as long as the window falls first within the dates of the time series.

There are a lot of functions in Pandas to calculate moving windows, such as `rolling_mean()`

, `rolling_std()`

, … See all of them here.

However, note that most of them will soon be deprecated, so it’s best to use a combination of the functions `rolling()`

with `mean()`

or `std()`

,… Depending of course on which type of moving window you want to calculate exactly.

But what does a moving window exactly mean for you?

The exact meaning, of course, depends on the statistic that you’re applying to the data. For example, a rolling mean smoothes out short-term fluctuations and highlight longer-term trends in data.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIElzb2xhdGUgdGhlIGFkanVzdGVkIGNsb3NpbmcgcHJpY2VzIFxuYWRqX2Nsb3NlX3B4ID0gYWFwbFsnX19fX19fX19fJ11cblxuIyBDYWxjdWxhdGUgdGhlIG1vdmluZyBhdmVyYWdlXG5tb3ZpbmdfYXZnID0gYWRqX2Nsb3NlX3B4Ll9fX19fX18od2luZG93PTQwKS5tZWFuKClcblxuIyBJbnNwZWN0IHRoZSByZXN1bHRcbnByaW50KF9fX19fX19fX19bLTEwOl0pIiwic29sdXRpb24iOiIjIElzb2xhdGUgdGhlIGFkanVzdGVkIGNsb3NpbmcgcHJpY2VzIFxuYWRqX2Nsb3NlX3B4ID0gYWFwbFsnQWRqIENsb3NlJ11cblxuIyBDYWxjdWxhdGUgdGhlIG1vdmluZyBhdmVyYWdlXG5tb3ZpbmdfYXZnID0gYWRqX2Nsb3NlX3B4LnJvbGxpbmcod2luZG93PTQwKS5tZWFuKClcblxuIyBJbnNwZWN0IHRoZSByZXN1bHRcbnByaW50KG1vdmluZ19hdmdbLTEwOl0pIiwic2N0IjoiRXgoKS50ZXN0X29iamVjdChcImFkal9jbG9zZV9weFwiKVxuRXgoKS50ZXN0X29iamVjdChcIm1vdmluZ19hdmdcIilcbkV4KCkudGVzdF9mdW5jdGlvbihcInByaW50XCIpXG5zdWNjZXNzX21zZyhcIllvdSBkaWQgYW4gYXdlc29tZSBqb2IgYXQgY2FsY3VsYXRpbmcgdGhlIG1vdmluZyBhdmVyYWdlIVwiKSJ9

**Tip**: try out some of the other standard moving windows functions that come with the Pandas package, such as `rolling_max()`

, `rolling_var()`

or `rolling_median()`

, in the IPython console. Note that you can also use `rolling()`

in combination with `max()`

, `var()`

or `median()`

to accomplish the same results! Remember that you can find more functions if you click on the link that’s provided in the text on top of this DataCamp Light chunk.

Of course, you might not really understand what all of this is about. Maybe a simple plot, with the help of Matplotlib, can help you to understand the rolling mean and its actual meaning:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSlcbmFkal9jbG9zZV9weCA9IGFhcGxbJ0FkaiBDbG9zZSddIiwic2FtcGxlIjoiIyBJbXBvcnQgbWF0cGxvdGxpYiBcbmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHRcblxuIyBTaG9ydCBtb3Zpbmcgd2luZG93IHJvbGxpbmcgbWVhblxuYWFwbFsnNDInXSA9IGFkal9jbG9zZV9weC5yb2xsaW5nKHdpbmRvdz00MCkubWVhbigpXG5cbiMgTG9uZyBtb3Zpbmcgd2luZG93IHJvbGxpbmcgbWVhblxuYWFwbFsnMjUyJ10gPSBhZGpfY2xvc2VfcHgucm9sbGluZyh3aW5kb3c9MjUyKS5tZWFuKClcblxuIyBQbG90IHRoZSBhZGp1c3RlZCBjbG9zaW5nIHByaWNlLCB0aGUgc2hvcnQgYW5kIGxvbmcgd2luZG93cyBvZiByb2xsaW5nIG1lYW5zXG5hYXBsW1snQWRqIENsb3NlJywgJzQyJywgJzI1MiddXS5wbG90KClcblxuIyBTaG93IHBsb3RcbnBsdC5zaG93KCkifQ==

The volatility of a stock is a measurement of the change in variance in the returns of a stock over a specific period of time. It is common to compare the volatility of a stock with another stock to get a feel for which may have less risk or to a market index to examine the stock’s volatility in the overall market. Generally, the higher the volatility, the riskier the investment in that stock, which results in investing in one over another.

the moving historical standard deviation of the log returns—i.e. the moving historical volatility—might be more of interest: Also make use of `pd.rolling_std(data, window=x) * math.sqrt(window)`

for the moving historical standard deviation of the log returns (aka the moving historical volatility).

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKVxuZGFpbHlfY2xvc2VfcHggPSBhYXBsW1snQWRqIENsb3NlJ11dXG5kYWlseV9wY3RfY2hhbmdlID0gZGFpbHlfY2xvc2VfcHgucGN0X2NoYW5nZSgpIiwic2FtcGxlIjoiIyBJbXBvcnQgbWF0cGxvdGxpYlxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdCBcblxuIyBEZWZpbmUgdGhlIG1pbnVtdW0gb2YgcGVyaW9kcyB0byBjb25zaWRlciBcbm1pbl9wZXJpb2RzID0gNzUgXG5cbiMgQ2FsY3VsYXRlIHRoZSB2b2xhdGlsaXR5XG52b2wgPSBkYWlseV9wY3RfY2hhbmdlLnJvbGxpbmcobWluX3BlcmlvZHMpLnN0ZCgpICogbnAuc3FydChtaW5fcGVyaW9kcykgXG5cbiMgUGxvdCB0aGUgdm9sYXRpbGl0eVxudm9sLnBsb3QoZmlnc2l6ZT0oMTAsIDgpKVxuXG4jIFNob3cgdGhlIHBsb3RcbnBsdC5zaG93KCkifQ==

The volatility is calculated by taking a rolling window standard deviation on the percentage change in a stock. You can clearly see this in the code because you pass `daily_pct_change`

and the `min_periods`

to `rolling_std()`

.

Note that the size of the window can and will change the overall result: if you take the window wider and make `min_periods`

larger, your result will become less representative. If you make it smaller and make the window more narrow, the result will come closer to the standard deviation.

Considering all of this, you see that it’s definitely a skill to get the right window size based upon the data sampling frequency.

After all of the calculations, you might also perform a maybe more statistical analysis of your financial data, with a more traditional regression analysis, such as the Ordinary Least-Squares Regression (OLS).

To do this, you have to make use of the `statsmodels`

library, which not only provides you with the classes and functions to estimate many different statistical models but also allows you to conduct statistical tests and perform statistical data exploration.

**Note** that you could indeed to the OLS regression with Pandas, but that the `ols`

module is now deprecated and will be removed in future versions. It is therefore wise to use the `statsmodels`

package.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IG51bXB5IGFzIG5wXG5pbXBvcnQgcGFuZGFzIGFzIHBkXG5hbGxfZGF0YSA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWxsX3N0b2NrX2RhdGEuY3N2XCIsIGluZGV4X2NvbD0gWzAsMV0sIGhlYWRlcj0wLCBwYXJzZV9kYXRlcz1bMF0pIiwic2FtcGxlIjoiIyBJbXBvcnQgdGhlIGBhcGlgIG1vZGVsIG9mIGBzdGF0c21vZGVsc2AgdW5kZXIgYWxpYXMgYHNtYFxuaW1wb3J0IHN0YXRzbW9kZWxzLmFwaSBhcyBzbVxuXG4jIEltcG9ydCB0aGUgYGRhdGV0b29sc2AgbW9kdWxlIGZyb20gYHBhbmRhc2BcbmZyb20gcGFuZGFzLmNvcmUgaW1wb3J0IGRhdGV0b29sc1xuXG4jIElzb2xhdGUgdGhlIGFkanVzdGVkIGNsb3NpbmcgcHJpY2VcbmFsbF9hZGpfY2xvc2UgPSBhbGxfZGF0YVtbJ0FkaiBDbG9zZSddXVxuXG4jIENhbGN1bGF0ZSB0aGUgcmV0dXJucyBcbmFsbF9yZXR1cm5zID0gbnAubG9nKGFsbF9hZGpfY2xvc2UgLyBhbGxfYWRqX2Nsb3NlLnNoaWZ0KDEpKVxuXG4jIElzb2xhdGUgdGhlIEFBUEwgcmV0dXJucyBcbmFhcGxfcmV0dXJucyA9IGFsbF9yZXR1cm5zLmlsb2NbYWxsX3JldHVybnMuaW5kZXguZ2V0X2xldmVsX3ZhbHVlcygnVGlja2VyJykgPT0gJ0FBUEwnXVxuYWFwbF9yZXR1cm5zLmluZGV4ID0gYWFwbF9yZXR1cm5zLmluZGV4LmRyb3BsZXZlbCgnVGlja2VyJylcblxuIyBJc29sYXRlIHRoZSBNU0ZUIHJldHVybnNcbm1zZnRfcmV0dXJucyA9IGFsbF9yZXR1cm5zLmlsb2NbYWxsX3JldHVybnMuaW5kZXguZ2V0X2xldmVsX3ZhbHVlcygnVGlja2VyJykgPT0gJ01TRlQnXVxubXNmdF9yZXR1cm5zLmluZGV4ID0gbXNmdF9yZXR1cm5zLmluZGV4LmRyb3BsZXZlbCgnVGlja2VyJylcblxuIyBCdWlsZCB1cCBhIG5ldyBEYXRhRnJhbWUgd2l0aCBBQVBMIGFuZCBNU0ZUIHJldHVybnNcbnJldHVybl9kYXRhID0gcGQuY29uY2F0KFthYXBsX3JldHVybnMsIG1zZnRfcmV0dXJuc10sIGF4aXM9MSlbMTpdXG5yZXR1cm5fZGF0YS5jb2x1bW5zID0gWydBQVBMJywgJ01TRlQnXVxuXG4jIEFkZCBhIGNvbnN0YW50IFxuWCA9IHNtLmFkZF9jb25zdGFudChyZXR1cm5fZGF0YVsnQUFQTCddKVxuXG4jIENvbnN0cnVjdCB0aGUgbW9kZWxcbm1vZGVsID0gc20uT0xTKHJldHVybl9kYXRhWydNU0ZUJ10sWCkuZml0KClcblxuIyBQcmludCB0aGUgc3VtbWFyeVxucHJpbnQobW9kZWwuc3VtbWFyeSgpKSJ9

Note that you add `[1:]`

to the concatenation of the AAPL and MSFT return data so that you don’t have any NaN values that can interfere with your model.

Things to look out for when you’re studying the result of the model summary are the following:

- The
`Dep. Variable`

, which indicates which variable is the response in the model - The
`Model`

in this case is`OLS`

. It’s the model you’re using in the fit - Additionally, you also have the
`Method`

to indicate how the parameters of the model were calculated. In this case, you see that this is set at`Least Squares`

.

Up until now, you haven’t seen much new information. You have basically set all of these in the code that you ran in the DataCamp Light chunk. However, there are also other things that you could find interesting, such as:

- The number of observations (
`No. Observations`

). Note that you could also derive this with the Pandas package by using the`info()`

function. Run`return_data.info()`

in the IPython console of the DataCamp Light chunk above to confirm this. - The degree of freedom of the residuals (
`DF Residuals`

) - The number of parameters in the model, indicated by
`DF Model`

; Note that the number doesn’t include the constant term`X`

which was defined in the code above.

This was basically the whole left column that you went over. The right column gives you some more insight into the goodness of the fit. You see, for example:

`R-squared`

, which is the coefficient of determination. This score indicates how well the regression line approximates the real data points. In this case, the result is`0.280`

. In percentages, this means that the score is at 28%. When the score is 0%, it indicates that the model explains none of the variability of the response data around its mean. Of course, a score of 100% indicates the opposite.- You also see the
`Adj. R-squared`

score, which at first sight gives the same number. However, the calculation behind this metric adjusts the R-Squared value based on the number of observations and the degrees-of-freedom of the residuals (registered in`DF Residuals`

). The adjustment in this case hasn’t had much effect, as the result of the adjusted score is still the same as the regular R-squared score. - The
`F-statistic`

measures how significant the fit is. It is calculated by dividing the mean squared error of the model by the mean squared error of the residuals. The F-statistic for this model is`514.2`

. - Next, there’s also the
`Prob (F-statistic)`

, which indicates the probability that you would get the result of the`F-statistic`

, given the null hypothesis that they are unrelated. - The
`Log-likelihood`

indicates the log of the likelihood function, which is, in this case`3513.2`

. - The
`AIC`

is the Akaike Information Criterion: this metric adjusts the log-likelihood based on the number of observations and the complexity of the model. The AIC of this model is`-7022`

. - Lastly, the
`BIC`

or the Bayesian Information Criterion, is similar to the AIC that you just have seen, but it penalizes models with more parameters more severely. Given the fact that this model only has one parameter (check`DF Model`

), the BIC score will be the same as the AIC score.

Below the first part of the model summary, you see reports for each of the model’s coefficients:

- The estimated value of the coefficient is registered at
`coef`

. `std err`

is the standard error of the estimate of the coefficient.- There’s also the t-statistic value, which you’ll find under
`t`

. This metric is used to measure how statistically significant a coefficient is. `P > |t|`

indicates the null-hypothesis that the coefficient = 0 is true. If it is less than the confidence level, often 0.05, it indicates that there is a statistically significant relationship between the term and the response. In this case, you see that the constant has a value of`0.198`

, while`AAPL`

is sset at`0.000`

.

Lastly, there is a final part of the model summary in which you’ll see other statistical tests to assess the distribution of the residuals:

`Omnibus`

, which is the Omnibus D’Angostino’s test: it provides a combined statistical test for the presence of skewness and kurtosis.- The
`Prob(Omnibus)`

is the`Omnibus`

metric turned into a probability. - Next, the
`Skew`

or Skewness measures the symmetry of the data about the mean. - The
`Kurtosis`

gives an indication of the shape of the distribution, as it compares the amount of data close to the mean with those far away from the mean (in the tails). `Durbin-Watson`

is a test for the presence of autocorrelation, and the`Jarque-Bera`

is another test of the skewness and kurtosis. You can also turn the result of this test into a probability, as you can see in`Prob (JB)`

.- Lastly, you have the
`Cond. No`

, which tests the multicollinearity.

You can plot the Ordinary Least-Squares Regression with the help of Matplotlib:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHN0YXRzbW9kZWxzLmFwaSBhcyBzbVxuaW1wb3J0IHBhbmRhcy50c2VyaWVzXG5pbXBvcnQgbnVtcHkgYXMgbnBcbmltcG9ydCBwYW5kYXMgYXMgcGRcbmFsbF9kYXRhID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hbGxfc3RvY2tfZGF0YS5jc3ZcIiwgaW5kZXhfY29sPSBbMCwxXSwgaGVhZGVyPTApXG5hbGxfYWRqX2Nsb3NlID0gYWxsX2RhdGFbWydBZGogQ2xvc2UnXV1cbmFsbF9yZXR1cm5zID0gbnAubG9nKGFsbF9hZGpfY2xvc2UgLyBhbGxfYWRqX2Nsb3NlLnNoaWZ0KDEpKVxuYWFwbF9yZXR1cm5zID0gYWxsX3JldHVybnMuaWxvY1thbGxfcmV0dXJucy5pbmRleC5nZXRfbGV2ZWxfdmFsdWVzKCdUaWNrZXInKSA9PSAnQUFQTCddXG5hYXBsX3JldHVybnMuaW5kZXggPSBhYXBsX3JldHVybnMuaW5kZXguZHJvcGxldmVsKCdUaWNrZXInKVxubXNmdF9yZXR1cm5zID0gYWxsX3JldHVybnMuaWxvY1thbGxfcmV0dXJucy5pbmRleC5nZXRfbGV2ZWxfdmFsdWVzKCdUaWNrZXInKSA9PSAnTVNGVCddXG5tc2Z0X3JldHVybnMuaW5kZXggPSBtc2Z0X3JldHVybnMuaW5kZXguZHJvcGxldmVsKCdUaWNrZXInKVxucmV0dXJuX2RhdGEgPSBwZC5jb25jYXQoW2FhcGxfcmV0dXJucywgbXNmdF9yZXR1cm5zXSwgYXhpcz0xKVsxOl1cbnJldHVybl9kYXRhLmNvbHVtbnMgPSBbJ0FBUEwnLCAnTVNGVCddXG5YID0gc20uYWRkX2NvbnN0YW50KHJldHVybl9kYXRhWydBQVBMJ10pXG5tb2RlbCA9IHNtLk9MUyhyZXR1cm5fZGF0YVsnTVNGVCddLFgpLmZpdCgpIiwic2FtcGxlIjoiIyBJbXBvcnQgbWF0cGxvdGxpYlxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdFxuXG4jIFBsb3QgcmV0dXJucyBvZiBBQVBMIGFuZCBNU0ZUXG5wbHQucGxvdChyZXR1cm5fZGF0YVsnQUFQTCddLCByZXR1cm5fZGF0YVsnTVNGVCddLCAnci4nKVxuXG4jIEFkZCBhbiBheGlzIHRvIHRoZSBwbG90XG5heCA9IHBsdC5heGlzKClcblxuIyBJbml0aWFsaXplIGB4YFxueCA9IG5wLmxpbnNwYWNlKGF4WzBdLCBheFsxXSArIDAuMDEpXG5cbiMgUGxvdCB0aGUgcmVncmVzc2lvbiBsaW5lXG5wbHQucGxvdCh4LCBtb2RlbC5wYXJhbXNbMF0gKyBtb2RlbC5wYXJhbXNbMV0gKiB4LCAnYicsIGx3PTIpXG5cbiMgQ3VzdG9taXplIHRoZSBwbG90XG5wbHQuZ3JpZChUcnVlKVxucGx0LmF4aXMoJ3RpZ2h0JylcbnBsdC54bGFiZWwoJ0FwcGxlIFJldHVybnMnKVxucGx0LnlsYWJlbCgnTWljcm9zb2Z0IHJldHVybnMnKVxuXG4jIFNob3cgdGhlIHBsb3RcbnBsdC5zaG93KCkifQ==

Note that you can also use the rolling correlation of returns as a way to crosscheck your results. You can handily make use of the Matplotlib integration with Pandas to call the `plot()`

function on the results of the rolling correlation:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IG51bXB5IGFzIG5wXG5pbXBvcnQgcGFuZGFzIGFzIHBkXG5hbGxfZGF0YSA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWxsX3N0b2NrX2RhdGEuY3N2XCIsIGluZGV4X2NvbD0gWzAsMV0sIGhlYWRlcj0wLCBwYXJzZV9kYXRlcz1bMV0pXG5hbGxfYWRqX2Nsb3NlID0gYWxsX2RhdGFbWydBZGogQ2xvc2UnXV1cbmFsbF9yZXR1cm5zID0gbnAubG9nKGFsbF9hZGpfY2xvc2UgLyBhbGxfYWRqX2Nsb3NlLnNoaWZ0KDEpKVxuYWFwbF9yZXR1cm5zID0gYWxsX3JldHVybnMuaWxvY1thbGxfcmV0dXJucy5pbmRleC5nZXRfbGV2ZWxfdmFsdWVzKCdUaWNrZXInKSA9PSAnQUFQTCddXG5hYXBsX3JldHVybnMuaW5kZXggPSBhYXBsX3JldHVybnMuaW5kZXguZHJvcGxldmVsKCdUaWNrZXInKVxubXNmdF9yZXR1cm5zID0gYWxsX3JldHVybnMuaWxvY1thbGxfcmV0dXJucy5pbmRleC5nZXRfbGV2ZWxfdmFsdWVzKCdUaWNrZXInKSA9PSAnTVNGVCddXG5tc2Z0X3JldHVybnMuaW5kZXggPSBtc2Z0X3JldHVybnMuaW5kZXguZHJvcGxldmVsKCdUaWNrZXInKVxucmV0dXJuX2RhdGEgPSBwZC5jb25jYXQoW2FhcGxfcmV0dXJucywgbXNmdF9yZXR1cm5zXSwgYXhpcz0xKVsxOl1cbnJldHVybl9kYXRhLmNvbHVtbnMgPSBbJ0FBUEwnLCAnTVNGVCddIiwic2FtcGxlIjoiIyBJbXBvcnQgbWF0cGxvdGxpYiBcbmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHRcblxuIyBQbG90IHRoZSByb2xsaW5nIGNvcnJlbGF0aW9uXG5yZXR1cm5fZGF0YVsnTVNGVCddLnJvbGxpbmcod2luZG93PTI1MikuY29ycihyZXR1cm5fZGF0YVsnQUFQTCddKS5wbG90KClcblxuIyBTaG93IHRoZSBwbG90XG5wbHQuc2hvdygpIn0=

Now that you have done some primary analyses to your data, it’s time to formulate your first trading strategy; But before you go into all of this, why not first get to know some of the most common trading strategies? After a short introduction, you’ll undoubtedly move on more easily your trading strategy.

From the introduction, you’ll still remember that a trading strategy is a fixed plan to go long or short in markets, but much more information you didn’t really get yet; In general, there are two common trading strategies: the momentum strategy and the reversion strategy.

Firstly, the **momentum strategy** is also called divergence or trend trading. When you follow this strategy, you do so because you believe the movement of a quantity will continue in its current direction. Stated differently, you believe that stocks have momentum or upward or downward trends, that you can detect and exploit.

Some examples of this strategy are the moving average crossover, the dual moving average crossover, and turtle trading:

- The moving average crossover is when the price of an asset moves from one side of a moving average to the other. This crossover represents a change in momentum and can be used as a point of making the decision to enter or exit the market. You’ll see an example of this strategy, which is the “hello world” of quantitative trading later on in this tutorial.
- The dual moving average crossover occurs when a short-term average crosses a long-term average. This signal is used to identify that momentum is shifting in the direction of the short-term average. A buy signal is generated when the short-term average crosses the long-term average and rises above it, while a sell signal is triggered by a short-term average crossing long-term average and falling below it.
- Turtle trading is a well-known trend following strategy that was originally taught by Richard Dennis. The basic strategy is to buy futures on a 20-day high and sell on a 20-day low.

Secondly, the **reversion strategy**, which is also known as convergence or cycle trading. This strategy departs from the belief that the movement of a quantity will eventually reverse. This might seem a little bit abstract, but will not be so anymore when you take the example. Take a look at the mean reversion strategy, where you actually believe that stocks return to their mean and that you can exploit when it deviates from that mean.

That already sounds a whole lot more practical, right?

Another example of this strategy, besides the mean reversion strategy, is the pairs trading mean-reversion, which is similar to the mean reversion strategy. Whereas the mean reversion strategy basically stated that stocks return to their mean, the pairs trading strategy extends this and states that if two stocks can be identified that have a relatively high correlation, the change in the difference in price between the two stocks can be used to signal trading events if one of the two moves out of correlation with the other. That means that if the correlation between two stocks has decreased, the stock with the higher price can be considered to be in a short position. It should be sold because the higher-priced stock will return to the mean. The lower-priced stock, on the other hand, will be in a long position because the price will rise as the correlation will return to normal.

Besides these two most frequent strategies, there are also other ones that you might come across once in a while, such as the forecasting strategy, which attempts to predict the direction or value of a stock, in this case, in subsequent future time periods based on certain historical factors. There’s also the High-Frequency Trading (HFT) strategy, which exploits the sub-millisecond market microstructure.

That’s all music for the future for now; Let’s focus on developing your first trading strategy for now!

As you read above, you’ll start with the “hello world” of quantitative trading: the moving average crossover. The strategy that you’ll be developing is simple: you create two separate Simple Moving Averages (SMA) of a time series with differing lookback periods, let’s say, 40 days and 100 days. If the short moving average exceeds the long moving average then you go long, if the long moving average exceeds the short moving average then you exit.

**Remember** that when you go long, you think that the stock price will go up and will sell at a higher price in the future (= buy signal); When you go short, you sell your stock, expecting that you can buy it back at a lower price and realize a profit (= sell signal).

This simple strategy might seem quite complex when you’re just starting out, but let’s take this step by step:

- First define your two different lookback periods: a short window and a long window. You set up two variables and assign one integer per variable. Make sure that the integer that you assign to the short window is shorter than the integer that you assign to the long window variable!
- Next, make an empty
`signals`

DataFrame, but do make sure to copy the index of your`aapl`

data so that you can start calculating the daily buy or sell signal for your`aapl`

data. - Create a column in your empty
`signals`

DataFrame that is named`signal`

and initialize it by setting the value for all rows in this column to`0.0`

. - After the preparatory work, it’s time to create the set of short and long simple moving averages over the respective long and short time windows. Make use of the
`rolling()`

function to start your rolling window calculcations: within the function, specify the`window`

and the`min_period`

, and set the`center`

argument. In practice, this will result in a`rolling()`

function to which you have passed either`short_window`

or`long_window`

,`1`

as the minimum number of observations in the window that are required to have a value, and`False`

, so that the labels are not set at the center of the window. Next, don’t forget to also chain the`mean()`

function so that you calculate the rolling mean. - After you have calculated the mean average of the short and long windows, you should create a signal when the short moving average crosses the long moving average, but only for the period greater than the shortest moving average window. In Python, this will result in a condition:
`signals['short_mavg'][short_window:] > signals['long_mavg'][short_window:]`

. Note that you add the`[short_window:]`

to comply with the condition “only for the period greater than the shortest moving average window”. When the condition is true, the initialized value`0.0`

in the`signal`

column will be overwitten with`1.0`

. A “signal” is created! If the condition is false, the original value of`0.0`

will be kept and no signal is generated. You use the NumPy`where()`

function to set up this condition. Much the same like you read just now, the variable to which you assign this result is`signals['signal'][short_window]`

, because you only want to create signals for the period greater than the shortest moving average window! - Lastly, you take the difference of the signals in order to generate actual trading orders. In other words, in this column of your
`signals`

DataFrame, you’ll be able to distinguish between long and short positions, whether you’re buying or selling stock.

Try all of this out in the DataCamp Light chunk below:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKSIsInNhbXBsZSI6IiMgSW5pdGlhbGl6ZSB0aGUgc2hvcnQgYW5kIGxvbmcgd2luZG93c1xuc2hvcnRfd2luZG93ID0gNDBcbmxvbmdfd2luZG93ID0gMTAwXG5cbiMgSW5pdGlhbGl6ZSB0aGUgYHNpZ25hbHNgIERhdGFGcmFtZSB3aXRoIHRoZSBgc2lnbmFsYCBjb2x1bW5cbnNpZ25hbHMgPSBwZC5EYXRhRnJhbWUoaW5kZXg9YWFwbC5pbmRleClcbnNpZ25hbHNbJ3NpZ25hbCddID0gMC4wXG5cbiMgQ3JlYXRlIHNob3J0IHNpbXBsZSBtb3ZpbmcgYXZlcmFnZSBvdmVyIHRoZSBzaG9ydCB3aW5kb3dcbnNpZ25hbHNbJ3Nob3J0X21hdmcnXSA9IGFhcGxbJ0Nsb3NlJ10ucm9sbGluZyh3aW5kb3c9c2hvcnRfd2luZG93LCBtaW5fcGVyaW9kcz0xLCBjZW50ZXI9RmFsc2UpLm1lYW4oKVxuXG4jIENyZWF0ZSBsb25nIHNpbXBsZSBtb3ZpbmcgYXZlcmFnZSBvdmVyIHRoZSBsb25nIHdpbmRvd1xuc2lnbmFsc1snbG9uZ19tYXZnJ10gPSBhYXBsWydDbG9zZSddLnJvbGxpbmcod2luZG93PWxvbmdfd2luZG93LCBtaW5fcGVyaW9kcz0xLCBjZW50ZXI9RmFsc2UpLm1lYW4oKVxuXG4jIENyZWF0ZSBzaWduYWxzXG5zaWduYWxzWydzaWduYWwnXVtzaG9ydF93aW5kb3c6XSA9IG5wLndoZXJlKHNpZ25hbHNbJ3Nob3J0X21hdmcnXVtzaG9ydF93aW5kb3c6XSBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBzaWduYWxzWydsb25nX21hdmcnXVtzaG9ydF93aW5kb3c6XSwgMS4wLCAwLjApICAgXG5cbiMgR2VuZXJhdGUgdHJhZGluZyBvcmRlcnNcbnNpZ25hbHNbJ3Bvc2l0aW9ucyddID0gc2lnbmFsc1snc2lnbmFsJ10uZGlmZigpXG5cbiMgUHJpbnQgYHNpZ25hbHNgXG5wcmludChzaWduYWxzKSJ9

This wasn’t too hard, was it? Print out the `signals`

DataFrame and inspect the results. Important to grasp here is what the `positions`

and the `signal`

columns mean in this DataFrame. You’ll see that it will become very important when you move on!

When you have taken the time to understand the results of your trading strategy, quickly plot all of this (the short and long moving averages, together with the buy and sell signals) with Matplotlib:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKVxuc2hvcnRfd2luZG93ID0gNDBcbmxvbmdfd2luZG93ID0gMTAwXG5zaWduYWxzID0gcGQuRGF0YUZyYW1lKGluZGV4PWFhcGwuaW5kZXgpXG5zaWduYWxzWydzaWduYWwnXSA9IDAuMFxuc2lnbmFsc1snc2hvcnRfbWF2ZyddID0gYWFwbFsnQ2xvc2UnXS5yb2xsaW5nKHdpbmRvdz1zaG9ydF93aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydsb25nX21hdmcnXSA9IGFhcGxbJ0Nsb3NlJ10ucm9sbGluZyh3aW5kb3c9bG9uZ193aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydzaWduYWwnXVtzaG9ydF93aW5kb3c6XSA9IG5wLndoZXJlKHNpZ25hbHNbJ3Nob3J0X21hdmcnXVtzaG9ydF93aW5kb3c6XSBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBzaWduYWxzWydsb25nX21hdmcnXVtzaG9ydF93aW5kb3c6XSwgMS4wLCAwLjApICAgXG5zaWduYWxzWydwb3NpdGlvbnMnXSA9IHNpZ25hbHNbJ3NpZ25hbCddLmRpZmYoKSIsInNhbXBsZSI6IiMgSW1wb3J0IGBweXBsb3RgIG1vZHVsZSBhcyBgcGx0YFxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdFxuXG4jIEluaXRpYWxpemUgdGhlIHBsb3QgZmlndXJlXG5maWcgPSBwbHQuZmlndXJlKClcblxuIyBBZGQgYSBzdWJwbG90IGFuZCBsYWJlbCBmb3IgeS1heGlzXG5heDEgPSBmaWcuYWRkX3N1YnBsb3QoMTExLCAgeWxhYmVsPSdQcmljZSBpbiAkJylcblxuIyBQbG90IHRoZSBjbG9zaW5nIHByaWNlXG5hYXBsWydDbG9zZSddLnBsb3QoYXg9YXgxLCBjb2xvcj0ncicsIGx3PTIuKVxuXG4jIFBsb3QgdGhlIHNob3J0IGFuZCBsb25nIG1vdmluZyBhdmVyYWdlc1xuc2lnbmFsc1tbJ3Nob3J0X21hdmcnLCAnbG9uZ19tYXZnJ11dLnBsb3QoYXg9YXgxLCBsdz0yLilcblxuIyBQbG90IHRoZSBidXkgc2lnbmFsc1xuYXgxLnBsb3Qoc2lnbmFscy5sb2Nbc2lnbmFscy5wb3NpdGlvbnMgPT0gMS4wXS5pbmRleCwgXG4gICAgICAgICBzaWduYWxzLnNob3J0X21hdmdbc2lnbmFscy5wb3NpdGlvbnMgPT0gMS4wXSxcbiAgICAgICAgICdeJywgbWFya2Vyc2l6ZT0xMCwgY29sb3I9J20nKVxuICAgICAgICAgXG4jIFBsb3QgdGhlIHNlbGwgc2lnbmFsc1xuYXgxLnBsb3Qoc2lnbmFscy5sb2Nbc2lnbmFscy5wb3NpdGlvbnMgPT0gLTEuMF0uaW5kZXgsIFxuICAgICAgICAgc2lnbmFscy5zaG9ydF9tYXZnW3NpZ25hbHMucG9zaXRpb25zID09IC0xLjBdLFxuICAgICAgICAgJ3YnLCBtYXJrZXJzaXplPTEwLCBjb2xvcj0naycpXG4gICAgICAgICBcbiMgU2hvdyB0aGUgcGxvdFxucGx0LnNob3coKSJ9

The result is pretty cool, isn’t it?

## Backtesting The Trading Strategy

Now that you’ve got your trading strategy at hand, it’s a good idea to also backtest it and calculate its performance. But right before you go deeper into this, you might want to know just a little bit more about the pitfalls of backtesting, what components are needed in a backtester and what Python tools you can use to backtest your simple algorithm.

If, however, you’re already well up to date, you can simply move on to the implementation of your backtester!

Backtesting is, besides just “testing a trading strategy”, testing the strategy on relevant historical data to make sure that it’s an actual viable strategy before you start making moves. With backtesting, a trader can simulate and analyze the risk and profitability of trading with a specific strategy over a period of time. However, when you’re backtesting, it’s a good idea to keep in mind that there are some pitfalls, which might not be obvious to you when you’re just starting out.

For example, there are external events, such as market regime shifts, which are regulatory changes or macroeconomic events, which definitely influence your backtesting. Also, liquidity constraints, such as the ban of short sales, could affect your backtesting heavily.

Next, there are pitfalls which you might introduce yourself when you, for example, overfit a model (optimization bias), when you ignore strategy rules because you think it’s better like that (interference), or when you accidentally introduce information into past data (lookahead bias).

These are just a few pitfalls that you need to take into account mainly after this tutorial, when you go and make your own strategies and backtest them.

Besides the pitfalls, it’s good to know that your backtester usually consists of some four essential components, which should usually present in every backtester:

- A data handler, which is an interface to a set of data,
- A strategy, which generates a signal to go long or go short based on the data,
- A portfolio, which generates orders and manages Profit & Loss (also known as “PnL”), and
- An execution handler, which sends the order to the broker and receives the “fills” or signals that the stock has been bought or sold.

Besides these four components, there are many more that you can add to your backtester, depending on the complexity. You can definitely go a lot further than just these four components. However, for this beginner tutorial, you’ll just focus on getting these basic components to work in your code.

As you read above, a simple backtester consists of a strategy, a data handler, a portfolio and an execution handler. You have already implemented a strategy above, and you also have access to a data handler, which is the `pandas-datareader`

or the Pandas library that you use to get your saved data from Excel into Python. The components that are still left to implement are the execution handler and the portfolio.

However, since you’re just starting out, you’ll not focus on implementing an execution handler just yet. Instead, you’ll see below how you can get started on creating a portfolio which can generate orders and manages the profit and loss:

- First off, you’ll create set a variable
`initial_capital`

to set your initial capital and a new DataFrame`positions`

. Once again, you copy the index from another DataFrame; In this case, this is the`signals`

DataFrame because you want to consider the time frame for which you have generated the signals. - Next, you create a new column
`AAPL`

in the DataFrame. On the days that the signal is 1 and the the short moving average crosses the long moving average (for the period greater than the shortest moving average window), you’ll buy a 100 shares. The days on which the signal is 0, the final result will be 0 as a result of the operation`100*signals['signal']`

. - A new DataFrame
`portfolio`

is created to store the market value of an open position. - Next, you create a DataFrame that stores the differences in positions (or number of stock)
- Then the real backtesting begins: you create a new column to the
`portfolio`

DataFrame with name`holdings`

, which stores the value of the positions or shares you have bought, multiplied by the ‘Adj Close’ price. - Your
`portfolio`

also contains a`cash`

column, which is the capital that you still have left to spend: it is calculated by taking your`initial_capital`

and subtracting your holdings (the price that you paid for buying stock). - You’ll also add a
`total`

column to your`portfolio`

DataFrame, which contains the sum of your cash and the holdings that you own, and - Lastly, you also add a
`returns`

column to your portfolio, in which you’ll store the returns

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKVxuc2hvcnRfd2luZG93ID0gNDBcbmxvbmdfd2luZG93ID0gMTAwXG5zaWduYWxzID0gcGQuRGF0YUZyYW1lKGluZGV4PWFhcGwuaW5kZXgpXG5zaWduYWxzWydzaWduYWwnXSA9IDAuMFxuc2lnbmFsc1snc2hvcnRfbWF2ZyddID0gYWFwbFsnQ2xvc2UnXS5yb2xsaW5nKHdpbmRvdz1zaG9ydF93aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydsb25nX21hdmcnXSA9IGFhcGxbJ0Nsb3NlJ10ucm9sbGluZyh3aW5kb3c9bG9uZ193aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydzaWduYWwnXVtzaG9ydF93aW5kb3c6XSA9IG5wLndoZXJlKHNpZ25hbHNbJ3Nob3J0X21hdmcnXVtzaG9ydF93aW5kb3c6XSBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBzaWduYWxzWydsb25nX21hdmcnXVtzaG9ydF93aW5kb3c6XSwgMS4wLCAwLjApICAgXG5zaWduYWxzWydwb3NpdGlvbnMnXSA9IHNpZ25hbHNbJ3NpZ25hbCddLmRpZmYoKSIsInNhbXBsZSI6IiMgU2V0IHRoZSBpbml0aWFsIGNhcGl0YWxcbmluaXRpYWxfY2FwaXRhbD0gZmxvYXQoMTAwMDAwLjApXG5cbiMgQ3JlYXRlIGEgRGF0YUZyYW1lIGBwb3NpdGlvbnNgXG5wb3NpdGlvbnMgPSBwZC5EYXRhRnJhbWUoaW5kZXg9c2lnbmFscy5pbmRleCkuZmlsbG5hKDAuMClcblxuIyBCdXkgYSAxMDAgc2hhcmVzXG5wb3NpdGlvbnNbJ0FBUEwnXSA9IDEwMCpzaWduYWxzWydzaWduYWwnXSAgIFxuICBcbiMgSW5pdGlhbGl6ZSB0aGUgcG9ydGZvbGlvIHdpdGggdmFsdWUgb3duZWQgICBcbnBvcnRmb2xpbyA9IHBvc2l0aW9ucy5tdWx0aXBseShhYXBsWydBZGogQ2xvc2UnXSwgYXhpcz0wKVxuXG4jIFN0b3JlIHRoZSBkaWZmZXJlbmNlIGluIHNoYXJlcyBvd25lZCBcbnBvc19kaWZmID0gcG9zaXRpb25zLmRpZmYoKVxuXG4jIEFkZCBgaG9sZGluZ3NgIHRvIHBvcnRmb2xpb1xucG9ydGZvbGlvWydob2xkaW5ncyddID0gKHBvc2l0aW9ucy5tdWx0aXBseShhYXBsWydBZGogQ2xvc2UnXSwgYXhpcz0wKSkuc3VtKGF4aXM9MSlcblxuIyBBZGQgYGNhc2hgIHRvIHBvcnRmb2xpb1xucG9ydGZvbGlvWydjYXNoJ10gPSBpbml0aWFsX2NhcGl0YWwgLSAocG9zX2RpZmYubXVsdGlwbHkoYWFwbFsnQWRqIENsb3NlJ10sIGF4aXM9MCkpLnN1bShheGlzPTEpLmN1bXN1bSgpICAgXG5cbiMgQWRkIGB0b3RhbGAgdG8gcG9ydGZvbGlvXG5wb3J0Zm9saW9bJ3RvdGFsJ10gPSBwb3J0Zm9saW9bJ2Nhc2gnXSArIHBvcnRmb2xpb1snaG9sZGluZ3MnXVxuXG4jIEFkZCBgcmV0dXJuc2AgdG8gcG9ydGZvbGlvXG5wb3J0Zm9saW9bJ3JldHVybnMnXSA9IHBvcnRmb2xpb1sndG90YWwnXS5wY3RfY2hhbmdlKClcblxuIyBQcmludCB0aGUgZmlyc3QgbGluZXMgb2YgYHBvcnRmb2xpb2BcbnByaW50KHBvcnRmb2xpby5oZWFkKCkpIn0=

As a last exercise for your backtest, visualize the portfolio value or `portfolio['total']`

over the years with the help of Matplotlib and the results of your backtest:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKVxuc2hvcnRfd2luZG93ID0gNDBcbmxvbmdfd2luZG93ID0gMTAwXG5zaWduYWxzID0gcGQuRGF0YUZyYW1lKGluZGV4PWFhcGwuaW5kZXgpXG5zaWduYWxzWydzaWduYWwnXSA9IDAuMFxuc2lnbmFsc1snc2hvcnRfbWF2ZyddID0gYWFwbFsnQ2xvc2UnXS5yb2xsaW5nKHdpbmRvdz1zaG9ydF93aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydsb25nX21hdmcnXSA9IGFhcGxbJ0Nsb3NlJ10ucm9sbGluZyh3aW5kb3c9bG9uZ193aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydzaWduYWwnXVtzaG9ydF93aW5kb3c6XSA9IG5wLndoZXJlKHNpZ25hbHNbJ3Nob3J0X21hdmcnXVtzaG9ydF93aW5kb3c6XSBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBzaWduYWxzWydsb25nX21hdmcnXVtzaG9ydF93aW5kb3c6XSwgMS4wLCAwLjApICAgXG5zaWduYWxzWydwb3NpdGlvbnMnXSA9IHNpZ25hbHNbJ3NpZ25hbCddLmRpZmYoKVxuaW5pdGlhbF9jYXBpdGFsPSBmbG9hdCgxMDAwMDAuMClcbnBvc2l0aW9ucyA9IHBkLkRhdGFGcmFtZShpbmRleD1zaWduYWxzLmluZGV4KS5maWxsbmEoMC4wKVxucG9zaXRpb25zWydBQVBMJ10gPSAxMDAqc2lnbmFsc1snc2lnbmFsJ10gICBcbnBvcnRmb2xpbyA9IHBvc2l0aW9ucy5tdWx0aXBseShhYXBsWydBZGogQ2xvc2UnXSwgYXhpcz0wKVxucG9zX2RpZmYgPSBwb3NpdGlvbnMuZGlmZigpXG5wb3J0Zm9saW9bJ2hvbGRpbmdzJ10gPSAocG9zaXRpb25zLm11bHRpcGx5KGFhcGxbJ0FkaiBDbG9zZSddLCBheGlzPTApKS5zdW0oYXhpcz0xKVxucG9ydGZvbGlvWydjYXNoJ10gPSBpbml0aWFsX2NhcGl0YWwgLSAocG9zX2RpZmYubXVsdGlwbHkoYWFwbFsnQWRqIENsb3NlJ10sIGF4aXM9MCkpLnN1bShheGlzPTEpLmN1bXN1bSgpICAgXG5wb3J0Zm9saW9bJ3RvdGFsJ10gPSBwb3J0Zm9saW9bJ2Nhc2gnXSArIHBvcnRmb2xpb1snaG9sZGluZ3MnXVxucG9ydGZvbGlvWydyZXR1cm5zJ10gPSBwb3J0Zm9saW9bJ3RvdGFsJ10ucGN0X2NoYW5nZSgpIiwic2FtcGxlIjoiIyBJbXBvcnQgdGhlIGBweXBsb3RgIG1vZHVsZSBhcyBgcGx0YFxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdFxuXG4jIENyZWF0ZSBhIGZpZ3VyZVxuZmlnID0gcGx0LmZpZ3VyZSgpXG5cbmF4MSA9IGZpZy5hZGRfc3VicGxvdCgxMTEsIHlsYWJlbD0nUG9ydGZvbGlvIHZhbHVlIGluICQnKVxuXG4jIFBsb3QgdGhlIGVxdWl0eSBjdXJ2ZSBpbiBkb2xsYXJzXG5wb3J0Zm9saW9bJ3RvdGFsJ10ucGxvdChheD1heDEsIGx3PTIuKVxuXG5heDEucGxvdChwb3J0Zm9saW8ubG9jW3NpZ25hbHMucG9zaXRpb25zID09IDEuMF0uaW5kZXgsIFxuICAgICAgICAgcG9ydGZvbGlvLnRvdGFsW3NpZ25hbHMucG9zaXRpb25zID09IDEuMF0sXG4gICAgICAgICAnXicsIG1hcmtlcnNpemU9MTAsIGNvbG9yPSdtJylcbmF4MS5wbG90KHBvcnRmb2xpby5sb2Nbc2lnbmFscy5wb3NpdGlvbnMgPT0gLTEuMF0uaW5kZXgsIFxuICAgICAgICAgcG9ydGZvbGlvLnRvdGFsW3NpZ25hbHMucG9zaXRpb25zID09IC0xLjBdLFxuICAgICAgICAgJ3YnLCBtYXJrZXJzaXplPTEwLCBjb2xvcj0naycpXG5cbiMgU2hvdyB0aGUgcGxvdFxucGx0LnNob3coKSJ9

**Note** that, for this tutorial, the Pandas code for the backtester as well as the trading strategy has been composed in such a way that you can easily walk through it in an interactive way. In a real-life application, you might opt for a more object-oriented design with classes, which contain all the logic. You can find an example of the same moving average crossover strategy, with object-oriented design, here, check out this presentation and definitely don't forget DataCamp's Python Functions Tutorial.

You have seen now how you can implement a backtester with the Python’s popular data manipulation package Pandas. However, you can also see that it’s easy to make mistakes and that this might not be the most fail-safe option to use every time: you need to build most of the components from scratch, even though you already leverage Pandas to get your results.

That’s why it’s common to use a backtesting platform, such as Quantopian, for your backtesters. Quantopian is a free, community-centered, hosted platform for building and executing trading strategies. It’s powered by `zipline`

, a Python library for algorithmic trading. You can use the library locally, but for the purpose of this beginner tutorial, you’ll use **Quantopian** to write and backtest your algorithm. Before you can do this, though, make sure that you first sign up and log in.

Next, you can get started pretty easily. Click “New Algorithm” to start writing up your trading algorithm or select one of the examples that has already been coded up for you to get a better feeling of what you’re exactly dealing with :)

Let’s start simple and make a new algorithm, but still following our simple example of the moving average crossover, which is the standard example that you find in the zipline Quickstart guide.

It so happens that this example is very similar to the simple trading strategy that you implemented in the previous section. You see, though, that the structure in the code chunk below and in the screenshot above is somewhat different than what you have seen up until now in this tutorial, namely, you have two definitions that you start working from, namely `initialize()`

and `handle_data()`

:

`def initialize(context): context.sym = symbol('AAPL') context.i = 0 def handle_data(context, data): # Skip first 300 days to get full windows context.i += 1 if context.i < 300: return # Compute averages # history() has to be called with the same params # from above and returns a pandas dataframe. short_mavg = data.history(context.sym, 'price', 100, '1d').mean() long_mavg = data.history(context.sym, 'price', 300, '1d').mean() # Trading logic if short_mavg > long_mavg: # order_target orders as many shares as needed to # achieve the desired number of shares. order_target(context.sym, 100) elif short_mavg < long_mavg: order_target(context.sym, 0) # Save values for later inspection record(AAPL=data.current(context.sym, "price"), short_mavg=short_mavg, long_mavg=long_mavg)`

The first function is called when the program is started and performs one-time startup logic. As an argument, the `initialize()`

function takes a `context`

, which is used to store the state during a backtest or live trading and can be referenced in different parts of the algorithm, as you can see in the code below; You see that `context`

comes back, among others, in the definition of the first moving average window. You see that you assign the result of the lookup of a security (stock in this case) by its symbol, (`AAPL`

in this case) to `context.security`

.

The `handle_data()`

function is called once per minute during simulation or live-trading to decide what orders, if any, should be placed each minute. The function requires `context`

and `data`

as input: the `context`

is the same as the one that you read about just now, while the data is an object that stores several API functions, such as `current()`

to retrieve the most recent value of a given field(s) for a given asset(s) or `history()`

to get trailing windows of historical pricing or volume data. These API functions don’t come back in the code below and are not in the scope of this tutorial.

**Note** That the code that you type into the Quantopian console will only work on the platform itself and not in your local Jupyter Notebook, for example!

You’ll see that the `data`

object allows you to retrieve the `price`

, which is the forward-filled, returning last known price, if there is one. If there is none, an `NaN`

value will be returned.

Another object that you see in the code chunk above is the `portfolio`

, which stores important information about…. Your portfolio. As you can see in the piece of code `context.portfolio.positions`

, this object is stored in the context and is then also accessible in the core functions that `context`

has to offer to you as a user. Note that the `positions`

that you just read about, store Position objects and include information such as the number of shares and price paid as values. Additionally, you also see that the `portfolio`

also has a `cash`

property to retrieve the current amount of cash in your portfolio and that the `positions`

object also has an `amount`

property to explore the whole number of shares in a certain position.

The `order_target()`

places an order to adjust a position to a target number of shares. If there is no existing position in the asset, an order is placed for the full target number. If there is a position in the asset, an order is placed for the difference between the target number of shares or contracts and the number currently held. Placing a negative target order will result in a short position equal to the negative number specified.

**Tip**: if you have any more questions about the functions or objects, make sure to check the Quantopian Help page, which contains more information about all (and much more) that you have briefly seen in this tutorial.

When you have created your strategy with the `initialize()`

and `handle_data()`

functions (or copy-pasted the above code) into the console on the left-hand side of your interface, just press the “Build Algorithm” button to build the code and run a backtest. If you press the “Run Full Backtest” button, a full backtest is run, which is basically the same as the one that you run when you build the algorithm, but you’ll be able to see a lot more in detail. The backtesting, whether ‘simple’ or full, can take a while; Make sure to keep an eye out on the progress bar on top of the page!

You can find more information on how to get started with Quantopian here.

**Note** that Quantopian is an easy way to get started with zipline, but that you can always move on to using the library locally in, for example, your Jupyter notebook.

## Improving The Trading Strategy

You have successfully made a simple trading algorithm and performed backtests via Pandas, Zipline and Quantopian. It’s fair to say that you’ve been introduced to trading with Python. However, when you have coded up the trading strategy and backtested it, your work doesn’t stop yet; You might want to improve your strategy. There are one or more algorithms may be used to improve the model on a continuous basis, such as KMeans, k-Nearest Neighbors (KNN), Classification or Regression Trees and the Genetic Algorithm. This will be the topic of a future DataCamp tutorial.

Apart from the other algorithms you can use, you saw that you can improve your strategy by working with multi-symbol portfolios. Just incorporating one company or symbol into your strategy often doesn’t really say much. You’ll also see this coming back in the evaluation of your moving average crossover strategy. Other things that you can add or do differently is using a risk management framework or use event-driven backtesting to help mitigate the lookahead bias that you read about earlier. There are still many other ways in which you could improve your strategy, but for now, this is a good basis to start from!

## Evaluating Moving Average Crossover Strategy

Improving your strategy doesn’t mean that you’re finished just yet! You can easily use Pandas to calculate some metrics to further judge your simple trading strategy. First, you can use the **Sharpe ratio** to get to know whether your portfolio’s returns are the result of the fact that you decided to make smart investments or to take a lot of risks.

The ideal situation is, of course, that the returns are considerable but that the additional risk of investing is as small as possible. That’s why, the greater the portfolio’s Sharpe ratio, the better: the ratio between the returns and the additional risk that is incurred is quite OK. Usually, a ratio greater than 1 is acceptable by investors, 2 is very good and 3 is excellent.

Let’s see how your algorithm does!

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG51bXB5IGFzIG5wXG5hYXBsID0gcGQucmVhZF9jc3YoXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9hYXBsLmNzdlwiLCBoZWFkZXI9MCwgaW5kZXhfY29sPSAwLCBuYW1lcz1bJ09wZW4nLCAnSGlnaCcsICdMb3cnLCAnQ2xvc2UnLCAnVm9sdW1lJywgJ0FkaiBDbG9zZSddLCBwYXJzZV9kYXRlcz1UcnVlKVxuc2hvcnRfd2luZG93ID0gNDBcbmxvbmdfd2luZG93ID0gMTAwXG5zaWduYWxzID0gcGQuRGF0YUZyYW1lKGluZGV4PWFhcGwuaW5kZXgpXG5zaWduYWxzWydzaWduYWwnXSA9IDAuMFxuc2lnbmFsc1snc2hvcnRfbWF2ZyddID0gYWFwbFsnQ2xvc2UnXS5yb2xsaW5nKHdpbmRvdz1zaG9ydF93aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydsb25nX21hdmcnXSA9IGFhcGxbJ0Nsb3NlJ10ucm9sbGluZyh3aW5kb3c9bG9uZ193aW5kb3csIG1pbl9wZXJpb2RzPTEsIGNlbnRlcj1GYWxzZSkubWVhbigpXG5zaWduYWxzWydzaWduYWwnXVtzaG9ydF93aW5kb3c6XSA9IG5wLndoZXJlKHNpZ25hbHNbJ3Nob3J0X21hdmcnXVtzaG9ydF93aW5kb3c6XSBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBzaWduYWxzWydsb25nX21hdmcnXVtzaG9ydF93aW5kb3c6XSwgMS4wLCAwLjApICAgXG5zaWduYWxzWydwb3NpdGlvbnMnXSA9IHNpZ25hbHNbJ3NpZ25hbCddLmRpZmYoKVxuaW5pdGlhbF9jYXBpdGFsPSBmbG9hdCgxMDAwMDAuMClcbnBvc2l0aW9ucyA9IHBkLkRhdGFGcmFtZShpbmRleD1zaWduYWxzLmluZGV4KS5maWxsbmEoMC4wKVxucG9zaXRpb25zWydBQVBMJ10gPSAxMDAqc2lnbmFsc1snc2lnbmFsJ10gICBcbnBvcnRmb2xpbyA9IHBvc2l0aW9ucy5tdWx0aXBseShhYXBsWydBZGogQ2xvc2UnXSwgYXhpcz0wKVxucG9zX2RpZmYgPSBwb3NpdGlvbnMuZGlmZigpXG5wb3J0Zm9saW9bJ2hvbGRpbmdzJ109KHBvc2l0aW9ucy5tdWx0aXBseShhYXBsWydBZGogQ2xvc2UnXSwgYXhpcz0wKSkuc3VtKGF4aXM9MSlcbnBvcnRmb2xpb1snY2FzaCddID0gaW5pdGlhbF9jYXBpdGFsIC0gKHBvc19kaWZmLm11bHRpcGx5KGFhcGxbJ0FkaiBDbG9zZSddLCBheGlzPTApKS5zdW0oYXhpcz0xKS5jdW1zdW0oKSAgIFxucG9ydGZvbGlvWyd0b3RhbCddID0gcG9ydGZvbGlvWydjYXNoJ10gKyBwb3J0Zm9saW9bJ2hvbGRpbmdzJ11cbnBvcnRmb2xpb1sncmV0dXJucyddID0gcG9ydGZvbGlvWyd0b3RhbCddLnBjdF9jaGFuZ2UoKSIsInNhbXBsZSI6IiMgSXNvbGF0ZSB0aGUgcmV0dXJucyBvZiB5b3VyIHN0cmF0ZWd5XG5yZXR1cm5zID0gcG9ydGZvbGlvWydfX19fX19fXyddXG5cbiMgYW5udWFsaXplZCBTaGFycGUgcmF0aW9cbnNoYXJwZV9yYXRpbyA9IG5wLnNxcnQoMjUyKSAqIChyZXR1cm5zLm1lYW4oKSAvIHJldHVybnMuc3RkKCkpXG5cbiMgUHJpbnQgdGhlIFNoYXJwZSByYXRpb1xucHJpbnQoX19fX19fX19fX19fKSIsInNvbHV0aW9uIjoiIyBJc29sYXRlIHRoZSByZXR1cm5zIG9mIHlvdXIgc3RyYXRlZ3lcbnJldHVybnMgPSBwb3J0Zm9saW9bJ3JldHVybnMnXVxuXG4jIGFubnVhbGl6ZWQgU2hhcnBlIHJhdGlvXG5zaGFycGVfcmF0aW8gPSBucC5zcXJ0KDI1MikgKiAocmV0dXJucy5tZWFuKCkgLyByZXR1cm5zLnN0ZCgpKVxuXG4jIFByaW50IHRoZSBTaGFycGUgcmF0aW9cbnByaW50KHNoYXJwZV9yYXRpbykiLCJzY3QiOiJFeCgpLnRlc3Rfb2JqZWN0KFwicmV0dXJuc1wiKVxuRXgoKS50ZXN0X29iamVjdChcInNoYXJwZV9yYXRpb1wiKVxuRXgoKS50ZXN0X2Z1bmN0aW9uKFwicHJpbnRcIilcbnN1Y2Nlc3NfbXNnKFwiV2VsbCBkb25lISBZb3Ugc3VjY2Vzc2Z1bGx5IGNhbGN1bGF0ZWQgdGhlIFNoYXJwZSByYXRpbyEgTm93IHdoYXQgZG9lcyB0aGlzIHNjb3JlIHRlbGwgeW91P1wiKSJ9

**Note** that the risk free rate that is excluded in the definition of the Sharpe ratio for this tutorial and that the Sharpe ratio is usually not considered as a standalone: it’s usually compared to other stocks. The best way to approach this issue is thus by extending your original trading strategy with more data (from other companies)!

Next, you can also calculate a **Maximum Drawdown**, which is used to measure the the largest single drop from peak to bottom in the value of a portfolio, so before a new peak is achieved. In other words, the score indicates the risk of a portfolio chosen based on a certain strategy.

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIERlZmluZSBhIHRyYWlsaW5nIDI1MiB0cmFkaW5nIGRheSB3aW5kb3dcbndpbmRvdyA9IDI1MlxuXG4jIENhbGN1bGF0ZSB0aGUgbWF4IGRyYXdkb3duIGluIHRoZSBwYXN0IHdpbmRvdyBkYXlzIGZvciBlYWNoIGRheSBcbnJvbGxpbmdfbWF4ID0gYWFwbFsnQWRqIENsb3NlJ10ucm9sbGluZyh3aW5kb3csIG1pbl9wZXJpb2RzPTEpLm1heCgpXG5kYWlseV9kcmF3ZG93biA9IGFhcGxbJ0FkaiBDbG9zZSddL3JvbGxpbmdfbWF4IC0gMS4wXG5cbiMgQ2FsY3VsYXRlIHRoZSBtaW5pbXVtIChuZWdhdGl2ZSkgZGFpbHkgZHJhd2Rvd25cbm1heF9kYWlseV9kcmF3ZG93biA9IGRhaWx5X2RyYXdkb3duLnJvbGxpbmcod2luZG93LCBtaW5fcGVyaW9kcz0xKS5taW4oKVxuXG4jIFBsb3QgdGhlIHJlc3VsdHNcbmRhaWx5X2RyYXdkb3duLnBsb3QoKVxubWF4X2RhaWx5X2RyYXdkb3duLnBsb3QoKVxuXG4jIFNob3cgdGhlIHBsb3RcbnBsdC5zaG93KCkifQ==

**Note** that you set `min_periods`

to `1`

because you want to let the first 252 days data have an expanding window.

Next up is the **Compound Annual Growth Rate (CAGR)**, which provides you with a constant rate of return over the time period. In other words, the rate tells you what you really have at the end of your investment period. You can calculate this rate by first dividing the investments ending value (*EV*) by the investment’s beginning value (*BV*). You raise the result to the power of *1/n*, where *n* is the number of periods. You subtract 1 from the consequent result and there’s your CAGR!

Maybe a formula is more clear: \[(EV/BV)^{1/n} - 1\]

Note that, in the code chunk below, you’ll see that you consider days, so your *1* is adjusted to *365* days (which is equal to 1 year).

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IHBhbmRhcyBhcyBwZFxuaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdFxuYWFwbCA9IHBkLnJlYWRfY3N2KFwiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvYWFwbC5jc3ZcIiwgaGVhZGVyPTAsIGluZGV4X2NvbD0gMCwgbmFtZXM9WydPcGVuJywgJ0hpZ2gnLCAnTG93JywgJ0Nsb3NlJywgJ1ZvbHVtZScsICdBZGogQ2xvc2UnXSwgcGFyc2VfZGF0ZXM9VHJ1ZSkiLCJzYW1wbGUiOiIjIEdldCB0aGUgbnVtYmVyIG9mIGRheXMgaW4gYGFhcGxgXG5kYXlzID0gKGFhcGwuaW5kZXhbLTFdIC0gYWFwbC5pbmRleFswXSkuZGF5c1xuXG4jIENhbGN1bGF0ZSB0aGUgQ0FHUiBcbmNhZ3IgPSAoKCgoYWFwbFsnQWRqIENsb3NlJ11bLTFdKSAvIGFhcGxbJ0FkaiBDbG9zZSddWzFdKSkgKiogKDM2NS4wL2RheXMpKSAtIDFcblxuIyBQcmludCB0aGUgQ0FHUlxucHJpbnQoX19fXykiLCJzb2x1dGlvbiI6IiMgR2V0IHRoZSBudW1iZXIgb2YgZGF5cyBpbiBgYWFwbGBcbmRheXMgPSAoYWFwbC5pbmRleFstMV0gLSBhYXBsLmluZGV4WzBdKS5kYXlzXG5cbiMgQ2FsY3VsYXRlIHRoZSBDQUdSIFxuY2FnciA9ICgoKChhYXBsWydBZGogQ2xvc2UnXVstMV0pIC8gYWFwbFsnQWRqIENsb3NlJ11bMV0pKSAqKiAoMzY1LjAvZGF5cykpIC0gMVxuXG4jIFByaW50IHRoZSBDQUdSXG5wcmludChjYWdyKSIsInNjdCI6IkV4KCkudGVzdF9vYmplY3QoXCJkYXlzXCIpXG5FeCgpLnRlc3Rfb2JqZWN0KFwiY2FnclwiKVxuRXgoKS50ZXN0X2Z1bmN0aW9uKFwicHJpbnRcIilcbnN1Y2Nlc3NfbXNnKFwiQXdlc29tZSBqb2IhIE5vdyB3aGF0IGRvZXMgdGhpcyBzY29yZSB0ZWxsIHlvdT9cIikifQ==

Besides these two metrics, there are also many other that you could consider, such as the **distribution of returns**, **trade-level metrics**, …

Well done, you’ve made it through this Python Finance introduction tutorial! You’ve covered a lot of ground, but there’s still so much more for you to discover!

Check out Yves Hilpisch’s Python For Finance book, which is a great book for those who already have gathered some background into Finance, but not so much in Python. “Mastering Pandas for Data Science” by Michael Heydt is also recommended for those who want to get started with Finance in Python! Also make sure to check out Quantstart’s articles for guided tutorials on algorithmic trading and this complete series on Python programming for finance.

If you’re more interested in continuing your journey into finance with R, consider taking Datacamp’s Quantitative Analyst with R track. And in the meantime, keep posted for our second post on starting finance with Python and check out the Jupyter notebook of this tutorial.

The information provided on this site is not financial advice and none of the authors are financial professionals. The material provided on this Website should be used for informational purposes only and in no way should be relied upon for financial advice. We make no representations as to accuracy, completeness, suitability, or validity, of any information. We will not be liable for any errors, omissions, or any losses, injuries, or damages arising from its display or use. All information is provided AS IS with no warranties, and confers no rights. Also, note that such material is not updated regularly and some of the information may not, therefore, be current. Please be sure to consult your own financial advisor when making decisions regarding your financial management. The ideas and strategies mentioned in this blog should never be used without first assessing your own personal and financial situation, or without consulting a financial professional.