{"id":16252,"date":"2021-08-24T02:39:48","date_gmt":"2021-08-23T18:39:48","guid":{"rendered":"https:\/\/www.tejwin.com\/?post_type=insight&#038;p=16252"},"modified":"2024-07-03T17:24:08","modified_gmt":"2024-07-03T09:24:08","slug":"jim-slaters-zulu-principle","status":"publish","type":"insight","link":"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/","title":{"rendered":"Jim Slater\u2019s Zulu Principle"},"content":{"rendered":"\n<p>To construct a portfolio based on Jim Slater\u2019s principle<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter caption-align-center\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/0FDYcdxnZVpPiHGsS.jpg\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Photo Creds:&nbsp;<a href=\"https:\/\/www.thisismoney.co.uk\/money\/diyinvesting\/article-2425500\/Investing-legend-Jim-Slater-market-beating-stock-Zulu-Principle.html\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"ek-link\">This is MONEY<\/a><\/figcaption><\/figure>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_81 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a110d3ca45d8\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"ez-toc-cssicon\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a110d3ca45d8\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Preface\" >Preface<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#The_Editing_Environment_and_Modules_Required\" >The Editing Environment and Modules Required<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#The_Highlights_of_the_Article\" >The Highlights of the Article<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Quantitative_Indicators\" >Quantitative Indicators<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Fundamental_Conditions\" >Fundamental Conditions<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Market-side_conditions\" >Market-side conditions<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Paid_Database_Used\" >Paid Database Used<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Investing_Strategy_in_Practice\" >Investing Strategy in Practice<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Conclusion\" >Conclusion<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/tejwin20260323.j.webweb.today\/en\/insight\/jim-slaters-zulu-principle\/#Related_Link\" >Related Link<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\" id=\"9db9\"><span class=\"ez-toc-section\" id=\"Preface\"><\/span><strong>Preface<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p id=\"218e\">Jim Slater is one of the well-known U.K. investors. He used to write column articles of portfolio recommendation for Sunday Telegraph and was famous for earning around 68.9% return during the period between 1963 to 1965, while the U.K. stock market only grew at 3.6% at the same period. Jim Slater\u2019s \u2018Zulu Principle\u2019 stresses the importance of focusing on your own niche field, where you can take advantage of. Therefore, Jim Slater especially pays attention to small and medium size firms that have long-term profit growth and relative strength and adopts price\/earnings to growth ratio (PEG ratio) as an important standard for valuation, as the following shown:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>EPS growth exceeds 15% in four consecutive years<\/li>\n\n\n\n<li>PEG ratio is less than 1.2 and the expected PE ratio is less than 20<\/li>\n\n\n\n<li>High liquidity, Low debt ratio, abundant cash flow and positive profit in five consecutive years<\/li>\n\n\n\n<li>Firms that have competitive edge, like having a dominant brand<\/li>\n\n\n\n<li>Turnaround and thematic stocks, such as having a new product or new management team<\/li>\n\n\n\n<li>Small market capitalization, high relative strength of stock price and high insider stock ownership<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"08ff\"><span class=\"ez-toc-section\" id=\"The_Editing_Environment_and_Modules_Required\"><\/span><strong>The Editing Environment and Modules Required<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p id=\"970e\">We use Windows OS and Jupyter Notebook in this article<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">import pandas as pd<br>import numpy as np<br>import tejapi<br>import matplotlib.pyplot as plt<br>tejapi.ApiConfig.api_key = \"Your Key\"<br>tejapi.ApiConfig.ignoretz = True<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"0b94\"><span class=\"ez-toc-section\" id=\"The_Highlights_of_the_Article\"><\/span><strong>The Highlights of the Article<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Quantify Jim Slater\u2019s investing principles<\/li>\n\n\n\n<li>Stocks selection and return calculation<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"714a\"><span class=\"ez-toc-section\" id=\"Quantitative_Indicators\"><\/span><strong>Quantitative Indicators<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p id=\"22d9\">Since Jim Slater\u2019s stock-picking standards include some subjective judgement factors, we present the following objective and quantitative indicators based on them and also adjust them by considering Taiwan stock market environments<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6498\"><span class=\"ez-toc-section\" id=\"Fundamental_Conditions\"><\/span><strong>Fundamental Conditions<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p id=\"7dd8\"><em>Condition1: Firm market value &lt; Market average market value<\/em><\/p>\n\n\n\n<p id=\"d5aa\"><em>Condition2: Positive net incomes in the past five years<\/em><\/p>\n\n\n\n<p id=\"c4be\"><em>Condition3: Net income growth &gt; 15% in three consecutive years<\/em><\/p>\n\n\n\n<p id=\"c924\"><em>Condition4: Expected net income growth \u2265 15%<\/em><\/p>\n\n\n\n<p id=\"63ac\"><em>Condition5: 5-year average cash flow from operating &gt; 5-year average net income<\/em><\/p>\n\n\n\n<p id=\"65f6\"><em>Condition6: Recent cash flow from operating &gt; recent net income<\/em><\/p>\n\n\n\n<p id=\"28cd\"><em>Condition7: Recent operating margin \u2265 10%<\/em><\/p>\n\n\n\n<p id=\"b7df\"><em>Condition8: Recent return on capital employed \u2265 10%<\/em><\/p>\n\n\n\n<p id=\"8ca4\"><em>Condition9: Recent debt\/equity ratio &lt; 50%<\/em><\/p>\n\n\n\n<p id=\"d18d\"><em>Condition10: Recent shareholding ratio of directors and supervisors \u2265 20% or recent increase in this ratio<\/em><\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3592\"><span class=\"ez-toc-section\" id=\"Market-side_conditions\"><\/span><strong>Market-side conditions<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p id=\"3ac1\"><em>Condition11: Expected PE ratio \u2264 20<\/em><\/p>\n\n\n\n<p id=\"1ea1\"><em>Condition12: Expected PE ratio\/Expected net income growth \u2264 1.2<\/em><\/p>\n\n\n\n<p id=\"b0cc\"><em>Condition13: Monthly excess return &gt; 0<\/em><\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"c43b\"><span class=\"ez-toc-section\" id=\"Paid_Database_Used\"><\/span><strong>Paid Database Used<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/api.tej.com.tw\/columns.html?idCode=TWN%2FANPRCSTD\" rel=\"noreferrer noopener\" target=\"_blank\">Security Characteristics Document<\/a>: the code of the database is \u2018TWN\/ANPRCSTD\u2019, which includes the codes of the current listed firms<\/li>\n\n\n\n<li><a href=\"https:\/\/api.tej.com.tw\/columndoc.html?subId=62\" rel=\"noreferrer noopener\" target=\"_blank\">Consolidated Cumulative Financial Reports (All Industries)<\/a>: the code of the database is \u2018TWN\/AIM1A\u2019, which contains seasonal data such as market value, net income, net income growth, operating cash flow, operating margin, EBIT, total assets, current assets and debt\/equity ratio<\/li>\n\n\n\n<li><a href=\"https:\/\/api.tej.com.tw\/columndoc.html?subId=26\" rel=\"noreferrer noopener\" target=\"_blank\">Shareholding Status of Directors and Supervisors<\/a>: the code of the database is \u2018TWN\/ABSTN1\u2019, covering monthly insider shareholding ratio<\/li>\n\n\n\n<li><a href=\"https:\/\/api.tej.com.tw\/columns.html?idCode=TWN%2FAPRCD1\" rel=\"noreferrer noopener\" target=\"_blank\">Adjusted Daily Stock Price<\/a>: the code of the database is \u2018TWN\/APRCD1\u2019, which has daily PE ratio<\/li>\n\n\n\n<li><a href=\"https:\/\/api.tej.com.tw\/columns.html?idCode=TWN%2FAPRCD2\" rel=\"noreferrer noopener\" target=\"_blank\">Listed Firms Return<\/a>: the code of the database is \u2018TWN\/APRCD2\u2019, covering monthly excess return and yearly return<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"7785\"><span class=\"ez-toc-section\" id=\"Investing_Strategy_in_Practice\"><\/span><strong>Investing Strategy in Practice<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Stock-picking conditions:<strong>&nbsp;at least 9<\/strong>&nbsp;fundamental conditions should be fulfilled, but market-side conditions should&nbsp;<strong>all be satisfied<\/strong><\/li>\n\n\n\n<li>Portfolio holding period: to\u00a0<strong>avoid look-ahead bias<\/strong>, we adopt the approach proposed in<a href=\"https:\/\/medium.com\/tej-api-financial-data-anlaysis\/application-1-the-investing-strategy-of-benjamin-graham-the-founder-of-securities-analysis-5aca86beb28e\" class=\"ek-link\" target=\"_blank\" rel=\"noopener\">\u3010Application(1)\u3011The investing strategy of Benjamin Graham \u2014 the founder of securities analysis<\/a>, which takes Q4 financial reports announcement date as the portfolio formation date. For example, we assume complete 2004 financial data will be disclosed in 2005\/03\/31, so the portfolio based on it will be held between 2005\/03\/31 ~ 2006\/3\/31<\/li>\n\n\n\n<li>Portfolio return calculation: portfolio should be held<strong>&nbsp;in exact one year&nbsp;<\/strong>to calculate yearly return which also&nbsp;<strong>considers transaction costs<\/strong><\/li>\n<\/ul>\n\n\n\n<p id=\"bba9\"><strong>Step 1.&nbsp;<\/strong>Obtain the codes of TSE listed common stocks<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">security = tejapi.get('TWN\/ANPRCSTD',<br>                     paginate = True)<br>stock_list = security[(security['mkt'] == 'TSE') &amp; (security['stype'] == 'STOCK')]['coid'].tolist()<\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1kj8JBrnSIjXtL30HdN3XHg.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"cb70\"><strong>Step 2.&nbsp;<\/strong>Obtain all the data we need and create condition column<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#container for outputs \ndata = pd.DataFrame() \n\nfor coid in stock_list: \n    #Obtain financial data\n    finance = tejapi.get('TWN\/AIM1A',   \n                    coid = coid,\n                    mdate = {'gte':'2000-01-01'},\n                    opts = {'pivot':True, 'columns':&#91;'coid','mdate','MV','R531','R405','7210','R106','2402','0010','1100','R504']},\n                    paginate = True,)\n    #Select data in December to annualize the data\n    finance = finance&#91;finance&#91;'mdate'].dt.month == 12].reset_index(drop=True)\n    \n    #Add 'match year' column for the later combination purpose\n    finance&#91;'MatchYear'] = finance&#91;'mdate'].dt.year\n    \n    #Calculate expected net income growth by using 5-year moving average of net income growth \n    finance&#91;'ExpectedNetIncomeGrowth'] = finance&#91;'R531'].rolling(5).mean()\n    \n    #Calculate 5-year moving average of cash flow from operating activities\n    finance&#91;'5_YearAverageOperatingCashFlow'] = finance&#91;'7210'].rolling(5).mean()\n    \n    #Calculate 5-year moving average of net income\n    finance&#91;'5_YearAverageNetIncome'] = finance&#91;'R531'].rolling(5).mean()\n    \n    #Condition2: Positive net incomes in the past five years                      \n    finance&#91;'positive_profit'] = np.where(finance&#91;'R531'] &gt; 0, 1, 0)\n    finance&#91;'condition2'] = np.where(finance&#91;'positive_profit'].rolling(5).sum() == 5, 1, 0)\n    \n    #Condition3: Net income growth &gt; 15% in three consecutive years\n    finance&#91;'net_income_growth_higher_than_15'] = np.where(finance&#91;'R405'] &gt;= 15, 1, 0)\n    finance&#91;'condition3'] = np.where(finance&#91;'net_income_growth_higher_than_15'].rolling(3).sum() == 3, 1, 0)\n    \n    #Condition4: Expected net income growth \u2265 15% \n    finance&#91;'condition4'] = np.where(finance&#91;'ExpectedNetIncomeGrowth'] &gt;= 15, 1, 0)\n    \n    #Condition5: 5-year average cash flow from operating &gt; 5-year average net income\n    finance&#91;'condition5'] = np.where(finance&#91;'5_YearAverageOperatingCashFlow'] &gt; finance&#91;'5_YearAverageNetIncome'], 1, 0)\n    \n    #Condition6: Recent cash flow from operating &gt; recent net income\n    finance&#91;'condition6'] = np.where(finance&#91;'7210'] &gt; finance&#91;'R531'], 1, 0)\n    \n    #Condition7: Recent operating margin \u2265 10%\n    finance&#91;'condition7'] = np.where(finance&#91;'R106'] &gt;= 10, 1, 0)\n    \n    #Condition8: Recent return on capital employed \u2265 10%\n    finance&#91;'ROCE'] = (finance&#91;'2402']\/(finance&#91;'0010']-finance&#91;'1100']))*100\n    finance&#91;'condition8'] = np.where(finance&#91;'ROCE'] &gt;= 10, 1, 0)\n    \n    #Condition9: Recent debt\/equity ratio &lt; 50%\n    finance&#91;'condition9'] = np.where(finance&#91;'R504'] &lt; 50, 1, 0)\n    \n    #Remove NaN data\n    finance = finance.dropna().reset_index(drop=True)\n   \n    #Obtain shareholding ratio data\n    chip  = tejapi.get('TWN\/ABSTN1',\n                        coid = coid,\n                        mdate = {'gte':'2000-01-01'},\n                        opts = {'columns':&#91;'coid','mdate','fld005']},\n                        paginate = True)\n    \n    #Check if the latest shareholding ratio of insider increases\n    chip&#91;'if_shareholding_ratio_increase'] = np.where(chip&#91;'fld005'] &gt; chip&#91;'fld005'].shift(1),1,0)\n    \n    #Select February data, since the latest shareholding data we have at portfolio formation data is February data\n    chip = chip&#91;(chip&#91;'mdate'].dt.month == 2)].reset_index(drop=True)\n    \n    #Condition10: Recent shareholding ratio of directors and supervisors \u2265 20% or recent increase in this ratio\n    chip&#91;'condition10'] = np.where((chip&#91;'fld005'] &gt;= 20) | (chip&#91;'if_shareholding_ratio_increase'] == 1),1,0)\n    \n    #Add 'match year' column for the later combination purpose, the reason of 'minus 1' is because this ratio data matches last year's financial data\n    chip&#91;'MatchYear'] = chip&#91;'mdate'].dt.year - 1\n    \n    #Creat a temporary dataframe by merging finance data with ratio data on firm's code and matchyear\n    temp = finance.merge(chip, on = &#91;'coid','MatchYear'])\n    \n    #Store this temporary dataframe in data \n    data = data.append(temp).reset_index(drop = True)<\/code><\/pre>\n\n\n\n<p id=\"2e0f\">Each loop deals with each stock. Because of the huge amount of data obtained, it takes around 30 ~ 40 minutes. The procedure includes data frequency adjustment, using&nbsp;<code>np.where()<\/code>&nbsp;to create condition columns, combining data from different databases and storing the outputs in&nbsp;<code>data<\/code>. Besides, since the index might be disordered after selecting, adding, sorting or removing data, we usually add&nbsp;<code>reset_index(drop=True)<\/code>. The following is the final content of&nbsp;<code>data<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1Nz9HKSGSczi2AvxojEvpJw.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">data_cp = data.copy()<\/pre>\n\n\n\n<p id=\"9c6b\">To avoid modifying the raw data, we copy&nbsp;<code>data&nbsp;<\/code>and proceed it with&nbsp;<code>data_cp<\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#Calculate market average market value<br>avg_mv = data_cp.groupby(by = 'mdate_x')['MV'].mean()#Map market average market value to data_cp by date column<br>data_cp['MarketAverageMarketValue'] = data_cp['mdate_x'].map(avg_mv)#Condition1: Firm market value &lt; Market average market value<br>data_cp['condition1'] = np.where(data_cp['MV'] &lt; data_cp['MarketAverageMarketValue'], 1, 0)<\/pre>\n\n\n\n<p id=\"bd7b\">Once we have the market value of whole firms, we can now create&nbsp;<code>condition1<\/code>&nbsp;column. Here we use&nbsp;<code>map()<\/code>&nbsp;to map market average market value to&nbsp;<code>data_cp<\/code>&nbsp;by its date column.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1WZ4MNHT94AMYk96fUPaXYA.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">#We choose the columns we need<br>data_cp = data_cp[['coid','mdate_x','MV','ExpectedNetIncomeGrowth','condition1','condition2','condition3','condition4','condition5','condition6','condition7','condition8','condition9','condition10']]<br>#Calculate the score and select those higher than 9<br>data_cp['score'] = data_cp['condition1'] + data_cp['condition2'] + data_cp['condition3'] + data_cp['condition4'] + data_cp['condition5'] + data_cp['condition6'] + data_cp['condition7'] + data_cp['condition8'] + data_cp['condition9'] + data_cp['condition10']<br>data_cp = data_cp[data_cp['score'] &gt;= 9].sort_values(by = 'mdate_x').reset_index(drop=True) <\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1ZtA0xchd5_F4JLnxIwqZWQ.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"79b2\"><strong>Step 3.&nbsp;<\/strong>Market-side condition and portfolio return calculation<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Panel = pd.DataFrame()    #To store complete data for each stock  \nReturn = pd.DataFrame()   #To store portfolio return   \ndate_list = pd.DatetimeIndex(data_cp&#91;'mdate_x'].unique()) #Transform unique date into DatatimeIndex list\n\nfor date in date_list: \n    #Each year has a dataframe\n    table = data_cp&#91;data_cp&#91;'mdate_x'].dt.year == date.year].reset_index(drop=True)\n    \n    #Get the previous year's PE ratios at portfolio formation date\n    stocks = table&#91;'coid'].tolist()\n    pe_ratio = tejapi.get('TWN\/APRCD1',\n                             coid = stocks,\n                             opts = {'columns':&#91;'coid','mdate','per_tse']}, \n                             mdate = {'gte': date + pd.Timedelta(days = 120 - 365) , 'lte': date + pd.Timedelta(days = 120)},\n                             paginate = True)\n    \n    #Calculate one-year average PE ratio as expected PE ratio\n    pe_estimate = pe_ratio.groupby(by = 'coid').mean().reset_index() \n    \n    #Obtain the excess monthly return data\n    relative_performance = tejapi.get('TWN\/APRCD2',\n                             coid = stocks,\n                             opts = {'columns':&#91;'coid','mdate','rois_m']}, \n                             mdate = {'gte': date + pd.Timedelta(days = 120 - 5), 'lte': date + pd.Timedelta(days = 120)}, #We just need the data closest to portfolio date\n                             paginate = True)\n    \n    #Pick the last data for each stock\n    relative = relative_performance.groupby(by = 'coid').last().reset_index()\n    \n    #Combine expected PE with stock relative performance\n    merge = pe_estimate.merge(relative, on = 'coid')\n    \n    #Alter column name to combine with table \n    merge = merge.rename(columns = {'mdate':'mdate_x', 'per_tse':'ExpectedPE_ratio'})\n    merge = table.merge(merge&#91;&#91;'coid', 'ExpectedPE_ratio','rois_m']], on = 'coid')\n    \n    #Calculate PEG ratio\n    merge&#91;'PEG_ratio'] = merge&#91;'ExpectedPE_ratio']\/merge&#91;'ExpectedNetIncomeGrowth']\n    \n    #Filter by market-side conditions, get the final constituent stocks\n    final = merge&#91;(merge&#91;'ExpectedPE_ratio'] &lt;= 20)&amp;(merge&#91;'PEG_ratio'] &lt;= 1.2) &amp; (merge&#91;'rois_m'] &gt; 0)].reset_index(drop=True)\n    \n    #Calculate the weight by firm's market value\n    final&#91;'weight']  = final&#91;'MV']\/ final&#91;'MV'].sum() \n    \n    #Obtain return data (including market as benchmark)\n    stocks = final&#91;'coid'].tolist()\n    ret = tejapi.get('TWN\/APRCD2',\n            coid = stocks + &#91;'Y9997'], \n            paginate = True,\n            opts = {'columns':&#91;'coid','mdate','roi_y']}, \n            mdate = {'gte': date + pd.Timedelta(days = 120), 'lte': date + pd.Timedelta(days = 120+365)})\n    \n    #Period Return: get the last return data of each stock, which is yearly return\n    period_ret = ret.groupby(by = 'coid')&#91;'roi_y'].last().reset_index()\n    \n    #Assign date for later combination\n    period_ret&#91;'mdate_x'] = date \n    \n    #Combine it with final, outer can make sure market return data is not removed\n    temp = final.merge(period_ret,on = &#91;'coid','mdate_x'], how = 'outer')\n    \n    #Store this year's complete data\n    Panel = Panel.append(temp).reset_index(drop=True)\n    \n    #Hold the portfolio since 2005(built on 2004 data), 2020 year is excluded because its portfolio hasn't been held for a year\n    if 2020 &gt; date.year &gt;= 2004:  \n        #Calculate portfolio return and market return\n        fee = 0.1425*2 + 0.3\n        eq_port = temp.loc&#91;:,'roi_y'].values&#91;:-1].mean() - fee           #Equally-weighted portfolio return (excluding market return)\n        val_port = (temp&#91;'weight']*temp&#91;'roi_y']).dropna().sum() - fee   #Market-Cap-weighted portfolio return (excluding market return)\n        mkt = temp&#91;'roi_y'].values&#91;-1]                                   #Market return \n        #Store whole return\n        Return = Return.append(pd.DataFrame(np.array(&#91;date,eq_port,val_port,mkt]).reshape((1,4)),columns = &#91;'mdate_x','Equally-Weighted Portfolio Return','Market-Cap-Weighted Portfolio Return','Market Return'])).reset_index(drop=True)<\/code><\/pre>\n\n\n\n<p id=\"beab\">Here we use each year as one loop and make the second filtering by market-side conditions and calculate portfolio return. It\u2019s worth noting that the time window of PE ratio we obtain is the previous year at portfolio formation date. For example, if&nbsp;<code>mdate_x<\/code>&nbsp;is \u20182020\u201312\u201301\u2019, it means we\u2019ll construct the portfolio on \u20182021\u201303\u201331\u2019(120 days later) and we need PE ratio from \u20182020\u201303\u201331\u2019 to \u20182021\u201303\u201331\u2019). Since this portfolio will be held until \u20182022\u201303\u201331\u2019 which hasn\u2019t happened yet, we will exclude 2020-based portfolio while calculating portfolio return.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Panel<\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1P4b7aTFAwojWf0PfRDozpA.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">Return<\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1fdydkNo6rKVjAsz-J_eoLQ.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"3f60\"><strong>Step 4.&nbsp;<\/strong>Visualize cumulative return (Code can be found in Source Code)<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1hi0yvXo4HiKiav4DzEgCIQ.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"bb05\"><strong>Step 5.&nbsp;<\/strong>Performance (Code can be found in Source Code)<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/10K0iN8-rVLaymoQKSTf2LA.png\" alt=\"\"\/><\/figure>\n\n\n\n<p id=\"afc3\"><strong>Step 6.&nbsp;<\/strong>Constituent stocks of 2020-based portfolio (Code can be found in Source Code)<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/tejwin20260323.j.webweb.today\/wp-content\/uploads\/1As1ZQ0gUs_oMd97S4_WnTA.png\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"bcc0\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span><strong>Conclusion<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p id=\"68b2\">Due to the huge data that covers financial, shareholding status and market-side data, we suggest readers begin with fewer firms, shorter time windows or fewer stock selection standards. If the output meets your expectation, then you can examine it from a longer period. In addition to time length, the quality and various data are required. Therefore, we recommend readers to purchase different databases in&nbsp;<a href=\"https:\/\/eshop.tej.com.tw\/E-Shop\/Edata_caseIntro\/2\" rel=\"noreferrer noopener\" target=\"_blank\">TEJ E Shop<\/a>, in order to put those well-known investors\u2019 investing philosophy into practice!<\/p>\n\n\n\n<p id=\"4094\">The content of this webpage does not constitute any offer or solicitation to offer or recommendation of any investment product. There may be&nbsp;<strong>survivor bias<\/strong>&nbsp;existing since we use current listed companies. 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 the author.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"bfdd\"><span class=\"ez-toc-section\" id=\"Related_Link\"><\/span><strong>Related Link<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/api.tej.com.tw\/index.html\" rel=\"noreferrer noopener\" target=\"_blank\">TEJ API<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/eshop.tej.com.tw\/E-Shop\/Edata_intro\" rel=\"noreferrer noopener\" target=\"_blank\">TEJ E-Shop<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>To construct a portfolio based on Jim Slater\u2019s principle Preface Jim Slater is one of the well-known U.K. investors. He used to write column articles of portfolio recommendation for Sunday Telegraph and was famous for earning around 68.9% return during the period between 1963 to 1965, while the U.K. stock market only grew at 3.6% [&hellip;]<\/p>\n","protected":false},"featured_media":16254,"template":"","tags":[2620,2371,3000,3005],"insight-category":[690,50],"class_list":["post-16252","insight","type-insight","status-publish","has-post-thumbnail","hentry","tag-portfolio","tag-python","tag-stock-selection","tag-tejapi-application","insight-category-data-analysis","insight-category-fintech"],"acf":[],"_links":{"self":[{"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/insight\/16252","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/insight"}],"about":[{"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/types\/insight"}],"version-history":[{"count":1,"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/insight\/16252\/revisions"}],"predecessor-version":[{"id":24202,"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/insight\/16252\/revisions\/24202"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/media\/16254"}],"wp:attachment":[{"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/media?parent=16252"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/tags?post=16252"},{"taxonomy":"insight-category","embeddable":true,"href":"https:\/\/tejwin20260323.j.webweb.today\/en\/wp-json\/wp\/v2\/insight-category?post=16252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}