What will we investigate in this tutorial?
A key element to success in trading is to understand the market and the trend of the stock before you buy it. In this tutorial we will not cover how to read the market, but take a top-down analysis approach to stock prices. We will use what is called Multiple Time Frame Analysis on a stock starting with a 1-month, 1-week, and 1-day perspective. Finally, we will compare that with a Simple Moving Average with a monthly view.
Step 1: Gather the data with different time frames
We will use the Pandas-datareader library to collect the time series of a stock. The library has an endpoint to read data from Yahoo! Finance, which we will use as it does not require registration and can deliver the data we need.
import pandas_datareader as pdr import datetime as dt ticker = "MSFT" start = dt.datetime(2019, 1, 1) end = dt.datetime.now() day = pdr.get_data_yahoo(ticker, start, end, interval='d') week = pdr.get_data_yahoo(ticker, start, end, interval='wk') month = pdr.get_data_yahoo(ticker, start, end, interval='mo')
Where the key is to set the interval to ‘d’ (Day), ‘wk’ (Week), and ‘mo’ (Month).
This will give us 3 DataFrames, each indexed with different intervals.
Dayly.
High Low ... Volume Adj Close Date ... 2019-01-02 101.750000 98.940002 ... 35329300.0 98.860214 2019-01-03 100.190002 97.199997 ... 42579100.0 95.223351 2019-01-04 102.510002 98.930000 ... 44060600.0 99.652115 2019-01-07 103.269997 100.980003 ... 35656100.0 99.779205 2019-01-08 103.970001 101.709999 ... 31514400.0 100.502670
Weekly.
High Low ... Volume Adj Close Date ... 2019-01-01 103.269997 97.199997 ... 157625100.0 99.779205 2019-01-08 104.879997 101.260002 ... 150614100.0 99.769432 2019-01-15 107.900002 101.879997 ... 127262100.0 105.302940 2019-01-22 107.879997 104.660004 ... 142112700.0 102.731720 2019-01-29 106.379997 102.169998 ... 203449600.0 103.376968
Monthly.
High Low ... Volume Adj Close Date ... 2019-01-01 107.900002 97.199997 ... 7.142128e+08 102.096245 2019-02-01 113.239998 102.349998 ... 4.690959e+08 109.526405 2019-03-01 120.820000 108.800003 ... 5.890958e+08 115.796768 2019-04-01 131.369995 118.099998 ... 4.331577e+08 128.226700 2019-05-01 130.649994 123.040001 ... 5.472188e+08 121.432449 2019-06-01 138.399994 119.010002 ... 5.083165e+08 132.012497
Step 2: Combine data and interpolate missing points
The challenge to connect the DataFrames is that they have different index entries. If we add the data points from Daily with Weekly, there will be a lot of missing entries that Daily has, but Weekly does not have.
day week Date 2019-01-02 101.120003 NaN 2019-01-03 97.400002 NaN 2019-01-04 101.930000 NaN 2019-01-07 102.059998 NaN 2019-01-08 102.800003 102.050003 ... ... ... 2020-08-13 208.699997 NaN 2020-08-14 208.899994 NaN 2020-08-17 210.279999 NaN 2020-08-18 211.490005 209.699997 2020-08-19 209.699997 209.699997
To deal with that we can choose to interpolate by using the DataFrame interpolate function.
import pandas_datareader as pdr import datetime as dt import pandas as pd ticker = "MSFT" start = dt.datetime(2019, 1, 1) end = dt.datetime.now() day = pdr.get_data_yahoo(ticker, start, end, interval='d') week = pdr.get_data_yahoo(ticker, start, end, interval='wk') month = pdr.get_data_yahoo(ticker, start, end, interval='mo') data = pd.DataFrame() data['day'] = day['Close'] data['week'] = week['Close'] data['week'] = data['week'].interpolate(method='linear') print(data)
Which results in the following output.
day week Date 2019-01-02 101.120003 NaN 2019-01-03 97.400002 NaN 2019-01-04 101.930000 NaN 2019-01-07 102.059998 NaN 2019-01-08 102.800003 102.050003 ... ... ... 2020-08-13 208.699997 210.047998 2020-08-14 208.899994 209.931998 2020-08-17 210.279999 209.815997 2020-08-18 211.490005 209.699997 2020-08-19 209.699997 209.699997
Where the missing points (except the first entry) will be linearly put between. This can be done for months as well, but we need to be more careful because of three things. First, some dates (1st of the month) do not exist in the data DataFrame. To solve that we use an outer-join, which will include them. Second, this introduces some extra dates, which are not trading dates. Hence, we need to delete them afterwards, which we can do by deleting the column (drop) and removing rows with NA value (dropna). Thirdly, we also need to understand that the monthly view looks backwards. Hence, the 1st of January is first finalized the last day of January. Therefore we shift it back in the join.
import pandas_datareader as pdr import datetime as dt import pandas as pd ticker = "MSFT" start = dt.datetime(2019, 1, 1) end = dt.datetime.now() day = pdr.get_data_yahoo(ticker, start, end, interval='d') week = pdr.get_data_yahoo(ticker, start, end, interval='wk') month = pdr.get_data_yahoo(ticker, start, end, interval='mo') data = pd.DataFrame() data['day'] = day['Close'] data['week'] = week['Close'] data['week'] = data['week'].interpolate(method='index') data = data.join(month['Close'].shift(), how='outer') data['month'] = data['Close'].interpolate(method='index') data = data.drop(columns=['Close']).dropna() data['SMA20'] = data['day'].rolling(20).mean()
Step 3: Visualize the output and take a look at it
To visualize it is straight forward by using matplotlib.
import pandas_datareader as pdr import datetime as dt import matplotlib.pyplot as plt import pandas as pd ticker = "MSFT" start = dt.datetime(2019, 1, 1) end = dt.datetime.now() day = pdr.get_data_yahoo(ticker, start, end, interval='d') week = pdr.get_data_yahoo(ticker, start, end, interval='wk') month = pdr.get_data_yahoo(ticker, start, end, interval='mo') data = pd.DataFrame() data['day'] = day['Close'] data['week'] = week['Close'] data['week'] = data['week'].interpolate(method='index') data = data.join(month['Close'].shift(), how='outer') data['month'] = data['Close'].interpolate(method='index') data = data.drop(columns=['Close']).dropna() data.plot() plt.show()
Which results in the following graph.

As expected the monthly price is adjusted to be the closing day-price the day before. Hence, it looks like the monthly-curve is crossing the day-curve on the 1st every month (which is almost true).
To really appreciate the Multiple Time Frames Analysis, it is better to keep the graphs separate and interpret them each isolated.
Step 4: How to use these different Multiple Time Frame Analysis
Given the picture it is a good idea to start top down. First look at the monthly picture, which shows the overall trend.




In the case of MSFT it is a clear growing trend, with the exception of two declines. But the overall impression is a company in growth that does not seem to slow down. Even the Dow theory (see this tutorial on it) suggest that there will be secondary movements in a general bull trend.
Secondly, we will look at the weekly view.




Here your impression is a bit more volatile. It shows many smaller ups and downs, with a big one in March, 2020. It could also indicate a small decline in the growth right and the end. Also, the Dow theory could suggest that it will turn. Though it is not certain.
Finally, on the daily view it gives a more volatile picture, which can be used to when to enter the market.




Here you could also be a bit worried. Is this the start of a smaller bull market.
To sum up. In the month-view, we have concluded a growth. The week-view shows signs of possible change. Finally, the day-view is also showing signs of possible decline.
As an investor, and based on the above, I would not enter the market right now. If both the month-view and week-view showed growth, while the day-view decline, that would be a good indicator. You want the top level to show growth, while a day-view might show a small decline.
Finally, remember that you should not just use one way to interpret to enter the market or not.
Step 5: Is monthly the same as a Simple Moving Average?
Good question, I am glad you asked. The Simple Moving Average (SMA) can be calculated easy with DataFrames using rolling and mean function.
Best way is to just try it.
import pandas_datareader as pdr import datetime as dt import matplotlib.pyplot as plt import pandas as pd ticker = "MSFT" start = dt.datetime(2019, 1, 1) end = dt.datetime.now() day = pdr.get_data_yahoo(ticker, start, end, interval='d') week = pdr.get_data_yahoo(ticker, start, end, interval='wk') month = pdr.get_data_yahoo(ticker, start, end, interval='mo') data = pd.DataFrame() data['day'] = day['Close'] data['week'] = week['Close'] data['week'] = data['week'].interpolate(method='index') data = data.join(month['Close'].shift(), how='outer') data['month'] = data['Close'].interpolate(method='index') data = data.drop(columns=['Close']).dropna() data['SMA20'] = data['day'].rolling(20).mean() data.plot() plt.show()
As you see, the SMA is not as reactive on the in crisis in March, 2020, as the monthly view is. This shows a difference in them. This does not exclude the one from the other, but shows a difference in how they react.




Please remember, that the monthly view is first updated at the end of a month, while SMA is updated on a daily basis.
Other differences is that SMA is an average of the 20 last days, while the monthly is the actual value of the last day of a month (as we look at Close). This implies that the monthly view can be much more volatile than the SMA.
Conclusion
It is advised to make analysis from bigger time frames and zoom in. This way you first look at overall trends, and get a bigger picture of the market. This should eliminate not to fall into being focused on a small detail in the market, but understand it on a higher level.
As I assume people are looking at this with the intention to copy ideas, please make sure you point out weaknesses in creating interpolated values. Creating automated strategies (or letting an algorithm learn from these inputs) is very dangerous as your values create a “look ahead bias”:
2020-08-13 208.699997 210.047998
2020-08-14 208.899994 209.931998
2020-08-17 210.279999 209.815997 <— !!
2020-08-18 211.490005 209.699997 <— !!
2020-08-19 209.699997 209.699997
As an example: your daily view on data does not know about the future, therefore does not know about the 209.699 value yet. When closing at 210 or 211, you are suggesting your machine that it can use the future value of 209 form the 19th Aug. 2020 to estimate the drop of the daily prices.
Hi Shuhari,
Thank you for taking the time to write a comment.
I happy that you share your knowledge.
I am not sure I follow along – that is just me not fully understanding the context. You say there is a forward bias. In the above tutorial we use the Close price. Hence, I do not fully understand how the daily close price can be biased?
Please help me understand, so I can improve this tutorial.
Thank you so much.
Rune