【Application(6)】Warren E. Buffett’s Value Investing
Stock screening from Buffett’s investing principles.

Preface
Warren E. Buffett is the person who has made the most money from stocks in the history of the world. He returned to Omaha in 1956 and started with $100. As of August 1999, his total personal assets have reached $36 B, becoming the second richest person in U.S. in that time. Buffet’s investment principles are very simple. First, ignore the daily rise and fall of stock prices. Second, do not worry about changes in the overall economics situation. Third, invest with the mentality of buying a company instead of investing in stocks.
- Company:
a. Is this company simple and understandable?
b. Is operating history of this company stable?
c. Is the company’s long-term development prospects promising? - Operation:
a. Whether the operator is rational?
b. Whether the operator is honest and frank with his shareholders?
c. Whether the operator will blindly follow the action of other legal entites ? - Finance:
a. Focus on Return on Equity (ROE) rather than earnings per share (EPS).
b. Calculate discounted free cash flow (DCF).
c. Looking for high gross margin (GM).
d. For each dollars of retained earnings make sure that the company has created at least on dollar of market value. - Market:
a. What is the value of this company?
b. Whether we can buy stocks at a significant value discount, that is, obtain a margin of safty.
The Editing Environment and Modules Required
We use Windows OS and Jupyter Notebook in this article.
import tejapi
import pandas as pd
import numpy as np
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True
Note: Remember to replace ‘Your key’ with the one you applied for. The last line indicates that we ignore the time zone.
The highlights of the article
- Quantify investment principles
- Database search
- Data filtering:
loc
,groupby
,pivot_table
Quantitative Indicators
Due to part of principles cannot be quantified. Therefore, we choose only quantifiable principles. The basis of principles is to evaluate earning ability of company.
- Most recent year ROE > Industry average ROE:save to
set_1
- Three-year average ROE > 15%:save to
set_2
- Most recent year Gross margin > Industry average GM:save to
set_3
- Increase in market value within 7 years / Increase in retained earnings within 7 years > 1:save to
set_4
- (Most recent year FCF / FCF 7 year ago ) -1 > 1:save to
set_5
- Current market value / The discounted value of FCF in next 10 years < 1 :save to
set_6
Investing Strategy
We choose the stocks which are eligible, and buy on 2020/1/1, hold until 2020/12/31. Each condition will make a set to save eligible stocks. Finally, make the intersection to get portfolio.
When we comparing whether each dollar of retained earnings creates a dollar of market value, it involves whether the company has been listed for long enough. Therefore we selected the companies which are alive in 2020 and listed for more than 7 years. Due to the formula of ROE, we can improved by borrowing, so we exclude the industries with high debt ratio such as banking and finance holding.
Stock Pool
Step 1. Search listed company database
tejapi.search_table("上市日")

Step 2. We use TWN/AIND database. Filter choose listed before 2013 and exclude industry (28 & 29).
comp_data = tejapi.get('TWN/AIND',
elist_day1 ={'lt':'2013-01-01'},
ind = {'ne':('28', '30')},
mkt = 'TSE',
opts = {'columns':['coid', 'elist_day1',
'ind']},
chinese_column_name=True,
paginate=True
)

Obtain a list eligible companies and use it to create industry average data later.
comp_list = list(comp_data['公司簡稱'])
Step 3. Make industry dictionary
industry_list = comp_data["TEJ 產業別"].unique().tolist()
Create ROE dict
of all companies in industry.
industry_data = tejapi.get('TWN/AIND',
ind = industry_list,
mkt = 'TSE',
opts = {'columns':['coid', 'ind']},
chinese_column_name=True,
paginate=True
).reset_index(drop=True)
The dict of key
is industry and value
is list of companies.
industry_dict = {}
for i in industry_list:
industry_dict[i] = industry_data[industry_data['TEJ 產業別'] ==
i]['公司簡稱'].tolist()
For example, search the companies in industry 13.
industry_dict["13"]

1. Most recent year ROE > Industry average ROE
- Database TWN/AIM1A
The following stock selection methods are similar to this. This content will be more complicated. Readers can check the complete code if you do not understand.
Step 1. Obtain the ROE data.
ROE_data = tejapi.get('TWN/AIM1A',
coid = comp_list,
mdate= '2019-12-01',
opts={'pivot':True,
'columns':['coid', 'mdate', 'R103']},
chinese_column_name=True,
paginate=True)

Step 2. 迭 For loop to turn industry into dictionary. Create 2019 industry average dict.
industry_roe = {}
for i in industry_list:
data = tejapi.get('TWN/AIM1A',
coid = industry_dict[i],
mdate='2019-12-01',
opts={'pivot':True,
'columns':['coid', 'mdate', 'R103']},
chinese_column_name=True,
paginate=True).reset_index(drop=True)
industry_roe[i] = data.groupby('公司代碼').mean().mean()[0]


Step 3. 將 Mapping the industry average dict to get average ROE.
ROE_data['產業淨值報酬%'] = ROE_data['TEJ 產業別'].apply(lambda x: industry_roe[x])

Step 5. Save eligible companies to set_1
.
set_1 = set(ROE_data[ROE_data['ROE(A)-稅後'] > ROE_data['產業淨值報酬%']]['公司簡稱'])
2. Three-year average ROE > 15%
Choose 3-year data and operate like point 1method groupby
. Then get averaged numbermean
and save toset_2
.
ROE_data_3Y = tejapi.get('TWN/AIM1A',
coid=comp_list,
mdate=['2017-12-01','2018-12-01','2019-12-
01'],
opts={'pivot':True,
'columns':['coid', 'mdate', 'R103']},
paginate=True,
chinese_column_name=True,
)

3. Most recent year Gross margin > Industry average GM
The operation method is similar to point 1. We save eligible companies into set_3
.

4. Increase in market value within 7 years / Increase in retained earnings within 7 years > 1
Step 1. Obtain market value and retained earnings data.
MV_RE_data = tejapi.get('TWN/AIM1A',
coid = comp_list,
mdate= ['2019/12/01','2013/03/01'],
opts={'pivot':True,
'columns':['coid', 'mdate','MV','2341']},
chinese_column_name=True,
paginate=True
).reset_index(drop=True)

Step 2. pivot_table
MV_RE_data.pivot_table(index='公司代碼', columns='財報年月').reset_index()

Step 3. Subtract the two columns to get the added value.
MV_RE_data['保留盈餘增加值'] = MV_RE_data.iloc[:,2] - MV_RE_data.iloc[:,1]MV_RE_data['市值增加值'] = MV_RE_data.iloc[:,4] - MV_RE_data.iloc[:,3]
Step 4. Calculate the signal.
MV_RE_data['指標'] = MV_RE_data['市值增加值'] / MV_RE_data['保留盈餘增加值']
Step 5. Save eligible companies into set_4
.
set_4 = set(MV_RE_data[MV_RE_data['指標']>1]['公司代碼'])
5. (Most recent year FCF / FCF 7 year ago ) -1 > 1
Step 1. Obtain FCF data.
cash_data = tejapi.get('TWN/AIM1A',
coid= comp_list,
mdate=['2013-12-01', '2019-12-01'],
opts={'pivot':True,
'columns':['coid', 'mdate', 'R69B']},
paginate=True,
chinese_column_name=True,
)
Step 2. The operation method is similar to point 4. Use pivot_table
and Subtract the two columns.

Step 3. Save toset_5
set_5 = set(cash_data[cash_data['指標'] > 1].index)
6. Current market value / The discounted value of FCF in next 10 years. Database: TWN/AIM1A, code: R69B
- Calculate present and future value. We can import useful module
numpy_financial
. Its documentation is here. Typepip install numpy_financial
in terminal.
import numpy_financial as npf
For instance, a company 4-year FCF are 100 / -150 / -200 / 400. We can use NPV method to calculate its present value by setting discount rate 10%.
cash_flows = np.array([100, -150, -200, 400])
npf.npv(0.1, cash_flows)

- We use two-stage discount model. The growth rate of the first stage is 15% ( first 3 years) and 5% in stage two. Assuming that the discount rate remains unchanged which is 9%. The following defines the cash flow for the next 10 years, and y0 is the 2019 cash flow.
def Cashflows(y0):
y1 = y0 * 1.15
y2 = y1 * 1.15
y3 = y2 * 1.15
y4 = y3 * 1.05
y5 = y4 * 1.05
y6 = y5 * 1.05
y7 = y6 * 1.05
y8 = y7 * 1.05
y9 = y8 * 1.05
y10 = y9 * 1.05
cashflows = np.array([y1,y2,y3,y4,y5,y6,y7,y8,y9,y10])
return cashflows
Step 1. Obtain 2019 FCF and market value.
MV_cash_data = tejapi.get('TWN/AIM1A',
coid= comp_list,
mdate='2019-12-01',
opts={'pivot':True,
'columns':['coid', 'mdate', 'R69B',
'MV']},
paginate=True,
chinese_column_name=True,
).reset_index(drop=True)

Step 2. Present value of 10-year FCF
MV_cash_data['自由現金流量(D)'].apply(lambda x: npf.npv(0.09, Cashflows(x)))
Step 3. Calculate the signal.
MV_cash_data['指標'] = MV_cash_data['季底普通股市值'] / MV_cash_data['自由現金流量(D)'].apply(lambda x: npf.npv(0.09, Cashflows(x)))
Step 3. Save to set_6
set_6 = set(MV_cash_data[(MV_cash_data['指標']<1) & (MV_cash_data['指標']>0)]['公司代碼'])
Review portfolio performane
Coming to the final stage we are most looking forward to, take the intersection of each set to get our portfolio.
set_1 & set_2 & set_3 & set_4 & set_5 & set_6


Refer to 【Application(5)】Modular Backtesting System. We put this list into the system. Because the price gap of the stock is too large, we use equal weight to buy and hold. Obtain the return rate is

Conclusion
More proficient in operating database, more able to design personalized stock selection. You can also test various stock selection stratigies. The content of this article is more complicated and requires more effort to study. If you have interest on this topic, you can go to our official website. It provides various financial data to help you make better strategy.
The content of this webpage is not an investment device and does not constitute any offer or solicitation to offer or recommendation of any investment product. It is for learning purposes only and does not take into account your individual needs, investment objectives and specific financial circumstances. Investment involves risk. Past performance is not indicative of future performance. Readers are requested to use their personal independent thinking skills to make investment decisions on their own. If losses are incurred due to relevant suggestions, it will not be involved with author.
Source Code
Extended Reading
Related Link
You could give us encouragement by …
We will share financial database applications every week.
If you think today’s article is good, you can click on the applause icononce.
If you think it is awesome, you can hold the applause icon until 50 times.
If you have any feedback, please feel free to leave a comment below.