This is a simple example to show how you can use P/E ratio to make investment decision. Our investment of choice is NIFTY index for simplicity (Though you cannot invest directly in the NIFTY, you can invest in any one of 11 Exchange traded funds which are based on NIFTY)
Lets get into tools and strategies now. To downloading index historical data we are going to use NSEpy. For back-testing our strategy we are using backtrader. Install dependencies -
pip install nsepy backtrader
Our strategy is simple, allocate 100% of your funds to NIFTY when P/E ratio of NIFTY is below say 20 and sell all your holdings and cash out if P/E ratio is above 24. Rational - Buy low and sell high and we use P/E estimate how high or low the index is. P/E ratio tells us how undervalued or overvalued the stock/index. Higher the P/E ratio, more overpriced the stock is.
Download the data from NSE takes a significan time and you do not want to wait everytime you tweak your strategies. Therefore we download the data and save it to disk.
#%matplotlib inline from datetime import date import pandas as pd try: nifty = pd.read_csv('data/nifty17years_withPE.csv') print('Read from disk successful') except: print('Downloading from NSE') nifty = get_history('NIFTY', date(2000, 1, 1), date(2017, 10, 31), index=True) pe = get_index_pe_history('NIFTY', date(2000, 1, 1), date(2017, 10, 31)) nifty['PE'] = pe['P/E'] nifty.to_csv('data/nifty17years_withPE.csv')
Trying to reading from disk Read from disk successful
from backtrader.feeds import GenericCSVData """ By default downloaded data only has datetime, Open, High, Low, Close, Volume and Turnover. As we are adding one more parameter "PE", we can no longer use GenericCSVData reader provided by backtrader library without modification to base class. """ # Define the new parameter class GenericCSV_PE(GenericCSVData): # Add a 'pe' line to the inherited ones from the base class lines = ('pe',) # add the parameter to the parameters inherited from the base class params = (('pe', 8),) # Declare position of each column in csv file data = GenericCSV_PE(dataname='data/nifty17years_withPE.csv', dtformat=('%Y-%m-%d'), datetime=0, high=1, low=2, open=3, close=4, volume=5, pe=7, openinterest=-1, #fromdate=date(2017,1,1), #todate=date(2017,1,10) )
import backtrader as bt class PEInvesting(bt.SignalStrategy): def log(self, txt, dt=None): pass def __init__(self): # Keep a reference to the "close" line in the data dataseries self.dataclose = self.datas.close self.pe = self.datas.pe def next(self): curdate = self.datetime.date(ago=0) if self.pe < 21: self.log(self.dataclose) # Use 100% of the cash to buy nifty self.order_target_percent(target=1.0) if self.pe > 24: self.log(self.dataclose) # Sell everything self.order_target_percent(target=0)
Run the strategy, Get final portfolio value and plot the whole backtesting.
cerebro = bt.Cerebro() # Set our desired cash start cerebro.broker.setcash(1000000.0) cerebro.adddata(data) cerebro.addstrategy(PEInvesting) cerebro.run() print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) print('Final value is %.2f times the initial investment'%(cerebro.broker.getvalue()/1000000.0)) cerebro.plot()
Final Portfolio Value: 10450659.40 Final value is 10.45 times the initial investment
[[<matplotlib.figure.Figure at 0x7f43edbf7c50>]]
Play with different possible strategies, eg.
In next notebook I'll try to backtest for systematic investing (SIP) where we will invest every month and try different strategies for SIP.