官老前辈 (KYY) 的黄金法则能赚钱吗?

如果你在马来西亚股市混了一段日子,
我相信你一定有读过关于官有缘先生的文章,
官老前辈在商界和投资界都非常有名

他也跟大家分享他选股的黄金法则

My golden rule is the company must report increasing profit for 2 consecutive quarters and the price is selling below P/E 10.

来源 : https://koonyewyin.com/2019/03/16/investment-talk-on-17-march-2019-my-golden-rule-for-share-selection/

今天我们就来回测这个黄金法则

选股规则

  • 只选PE小于10的公司
  • 只选前10间连续两个季度EPS成长最高的公司
  • 没有计算交易成本
  • 每月重复以上步骤
import pandas as pd
from datetime import datetime
import warnings
import numpy as np
import matplotlib.pyplot as plt
from dateutil.relativedelta import relativedelta
import math
warnings.filterwarnings("ignore")
plt.style.use('seaborn')

stock_data = pd.read_csv('M.csv')
KLSE = pd.read_csv('MKLSE.csv')
codename = pd.read_csv('codename.csv')

stock_data['Change'] = (stock_data['Change']/100) + 1

def Code2Name(code):

    code = code.replace('KL','')
    row = codename.loc[codename['Code'] == code]
    return row['Name'].values[0]

def calculate_eps_growth(stock_data):
    stock_data['Changes_Next_Month'] = stock_data.groupby('Code')['Change'].shift(-1)

    stock_data['EPS_Increase'] = stock_data.groupby('Code')['EPS'].diff()
    stock_data['EPS_Increase'] = stock_data['EPS_Increase'].replace(0, None)
    stock_data['EPS_Increase'] = stock_data['EPS_Increase'].bfill()
    stock_data['Previous_EPS'] = stock_data['EPS'] - stock_data['EPS_Increase']

    stock_data['EPS_Increase_2'] = stock_data.groupby('Code')['Previous_EPS'].diff()
    stock_data['EPS_Increase_2'] = stock_data['EPS_Increase_2'].replace(0, None)
    stock_data['EPS_Increase_2'] = stock_data['EPS_Increase_2'].bfill()
    stock_data['Previous_EPS_2'] = stock_data['Previous_EPS'] - stock_data['EPS_Increase_2']

    stock_data['EPS_Increase'] = stock_data['EPS_Increase']/abs(stock_data['Previous_EPS']) + 1
    stock_data['EPS_Increase_2'] = stock_data['EPS_Increase_2']/abs(stock_data['Previous_EPS_2']) + 1 

    stock_data['2_Consecutive_EPS_Growth'] = (stock_data['EPS_Increase'] * stock_data['EPS_Increase_2'])
    stock_data = stock_data[~stock_data.isin([np.nan, np.inf, -np.inf]).any(1)]

    return stock_data

stock_data = calculate_eps_growth(stock_data)

NumberOfShares = 10
InitialCapital = 1000

def cagr(df):
    start = datetime.strptime(df.iloc[0].name, '%Y-%m-%d')
    end = datetime.strptime(df.iloc[-1].name, '%Y-%m-%d')

    num_periods = relativedelta(start, end).years

    return ((df['Capital'][0] / df['Capital'][-1]) ** (1 / (num_periods - 1)) - 1)*100.0

stock_data = stock_data[stock_data['PE'] <= 10]
stock_data = stock_data.sort_values(['Datetime','2_Consecutive_EPS_Growth'],ascending = False)
stock_data = stock_data.groupby(['Datetime']).head(NumberOfShares)

output = pd.DataFrame()
stock_data['Code'] += ' '
stock_data_groupby = stock_data.groupby('Datetime')
output['Shares_bought'] = stock_data_groupby['Code'].sum()
output['Number of shares'] = stock_data_groupby.size()
output['Average gains'] = stock_data_groupby['Changes_Next_Month'].mean()
output['Median gains'] = stock_data_groupby['Changes_Next_Month'].median()
output['Max gains'] = stock_data_groupby['Changes_Next_Month'].max()
output['Min gains'] = stock_data_groupby['Changes_Next_Month'].min()
output['Average gains'].replace(np.inf, 0, inplace=True)
KLSE = KLSE.set_index('Date')
output = output.join(KLSE['Change'])

output['Benchmark'] = 0
output['Capital'] = 0
output['Trading Fees'] = 0
output = output.dropna()

for i in range(0,len(output)):
    if i == 0:
        output['Capital'][i] = ((output['Average gains'][i]) * InitialCapital)
        output['Benchmark'][i] = (output['Change'][i] + 1.0) * InitialCapital
    else:
        #print(((output['Average gains'][i]+1.0).cumprod()*output['Capital'][i-1]) - NumberOfShares*TradingFees)
        output['Capital'][i] = ((output['Average gains'][i])*output['Capital'][i-1])
        output['Benchmark'][i] = (output['Change'][i] + 1.0)*output['Benchmark'][i-1]

output['Capital (No fees)'] = (output['Average gains']).cumprod()*InitialCapital
#output['Trading Fees'] = output['Capital (No fees)'] - output['Capital']
output['Average gains'] = output['Average gains']*100.0

CompoundedGrowth = cagr(output)

for index, row in output.iterrows():
    codes = row['Shares_bought'].split()
    names = [Code2Name(c) for c in codes]
    names = ' '.join(names)
    output.at[index,'Shares_bought'] = names

所以我们都买了什么股?

pd.set_option("display.max_rows", None, "display.max_columns", None)
print(output[['Shares_bought']].reset_index())
       Datetime                                      Shares_bought
0    2011-03-31  DNONCE MASTER KHIND RSAWIT ICAP MBSB ECOFIRS G...
1    2011-04-30  BLDPLNT SSTEEL INSAS DNONCE ASTINO YTL MALTON ...
2    2011-05-31  TNLOGIS SSTEEL ANALABS AMPROP INSAS SMCAP MAA ...
3    2011-06-30  TNLOGIS SSTEEL ANALABS AMPROP INSAS SMCAP MAA ...
4    2011-07-31  TNLOGIS SSTEEL SURIA ANALABS AMPROP INSAS SMCA...
5    2011-08-31  TANCO FN LFECORP ANALABS SMCAP ASTINO GUNUNG I...
6    2011-09-30  ARK TANCO FN SURIA SMCAP GUNUNG IREKA FCW GPHA...
7    2011-10-31  ARK TANCO FN SMCAP GUNUNG IREKA FCW GPHAROS KS...
8    2011-11-30  BINTAI DNEX KPPROP TGL KERJAYA HCK KPS SYCAL Q...
9    2011-12-31  SYF BINTAI DNEX KPPROP TGL KERJAYA IQGROUP IGB...
10   2012-01-31  PEB SYF BINTAI DNEX KPPROP TGL KERJAYA IQGROUP...
11   2012-02-29  PEB SYF TIMWELL FARLIM ENCORP CIHLDG VERTICE M...
12   2012-03-31  KYM PEB FARLIM ENCORP CIHLDG ACME VERTICE MJPE...
13   2012-04-30  KYM FARLIM ENCORP ACME VERTICE MJPERAK CFM SCO...
14   2012-05-31  ATTA KYM TPC ACME MJPERAK KUCHAI LG KNM PASDEC...
15   2012-06-30  ATTA TPC MJPERAK KUCHAI LG KNM PASDEC JOHOTIN ...
16   2012-07-31  ATTA TPC MJPERAK KUCHAI LG KNM PASDEC JOHOTIN ...
17   2012-08-31  DYNACIA KTB GESHEN OCB SEACERA LSTEEL PO VIZIO...
18   2012-09-30  DYNACIA KTB OCB SEACERA LSTEEL PO VIZIONE MESB...
19   2012-10-31  DYNACIA KTB PEB TMCLIFE GESHEN OCB SEACERA LST...
20   2012-11-30  MUIIND PEB TMCLIFE TGL NYLEX SHH PO GOB RGB LA...
21   2012-12-31  MUIIND PEB TMCLIFE TGL WATTA NYLEX PO GOB OCNC...
22   2013-01-31  MUIIND TGL WATTA PO GOB RGB LATITUD PPHB MFLOU...
23   2013-02-28  LIENHOE PMHLDG OSK MTDACPI MUH EMICO YLI DBHD ...
24   2013-03-31  LIENHOE PMHLDG OSK MTDACPI ADVENTA MUH EMICO Y...
25   2013-04-30  POLY LIENHOE PMHLDG OSK MTDACPI ADVENTA MUH EM...
26   2013-05-31  MTDACPI POLY ASIAPAC ADVENTA CHHB MCT LIONIND ...
27   2013-06-30  MTDACPI POLY ASIAPAC CHHB MCT LIONIND DSONIC G...
28   2013-07-31  MTDACPI ASIAPAC ICAP CHHB MCT LIONIND DSONIC D...
29   2013-08-31  HUBLINE APEX NOTION MMSV ICAP KTB TAWIN ENGTEX...
30   2013-09-30  HUBLINE APEX NOTION MMSV ICAP KTB TAWIN BORNOI...
31   2013-10-31  HUBLINE APEX NOTION MMSV KTB TAWIN BORNOIL ENG...
32   2013-11-30  KSTAR CAB IMPIANA FACBIND LBS DWL MINHO KSSC E...
33   2013-12-31  KSTAR VS POHUAT CAB IMPIANA FACBIND LBS DWL MI...
34   2014-01-31  KSTAR VS HIGHTEC POHUAT CAB IMPIANA FACBIND LB...
35   2014-02-28  VS HIGHTEC HARNLEN POHUAT PMHLDG VIZIONE JCY N...
36   2014-03-31  HARNLEN PMHLDG VIZIONE JCY NAIM MENTIGA OMESTI...
37   2014-04-30  HARNLEN PMHLDG VIZIONE JCY NAIM MENTIGA ICAP O...
38   2014-05-31  AMPROP MTDACPI SNC IQZAN SEACERA EURO SKBSHUT ...
39   2014-06-30  AMPROP MTDACPI SNC IQZAN SEACERA EURO SKBSHUT ...
40   2014-07-31  DNONCE AMPROP MTDACPI SNC IQZAN SEACERA EURO S...
41   2014-08-31  KIMHIN DNONCE PJBUMI MRCB GLOTEC BHIC PDZ KUCH...
42   2014-09-30  DNONCE PJBUMI MRCB GLOTEC BHIC HIGHTEC PDZ KUC...
43   2014-10-31  KIMHIN PJBUMI MRCB GLOTEC DNONCE BHIC HIGHTEC ...
44   2014-11-30  TGL TALIWRK DNONCE MINHO FCW EKSONS CHGP HIGHT...
45   2014-12-31  TALIWRK DNONCE MINHO FCW EKSONS BJFOOD BJCORP ...
46   2015-01-31  TALIWRK MINHO FCW EKSONS BJFOOD BJCORP CHGP PR...
47   2015-02-28  JCBNEXT LEWEKO EKSONS JADI BJFOOD BJCORP ARBB ...
48   2015-03-31  ICON JCBNEXT BJCORP LEWEKO EKSONS JADI ARBB GP...
49   2015-04-30  ICON JCBNEXT BJCORP LEWEKO EKSONS JADI ARBB GP...
50   2015-05-31  ASIAPAC EASTLND MENTIGA ATAIMS BJCORP RESINTC ...
51   2015-06-30  ASIAPAC EASTLND MENTIGA ATAIMS BJLAND RESINTC ...
52   2015-07-31  ASIAPAC MENTIGA BJLAND RESINTC DUTALND PENSONI...
53   2015-08-31  SEACERA GUOCO DAYA SUCCESS TADMAX YONGTAI BJLA...
54   2015-09-30  SEACERA GUOCO DAYA SUCCESS TADMAX YONGTAI MYSC...
55   2015-10-31  SEACERA GUOCO DAYA TADMAX YONGTAI MYSCM UMS PL...
56   2015-11-30  GPHAROS NGGB MYSCM JCBNEXT DAYA INCKEN TIGER T...
57   2015-12-31  GPHAROS NGGB MYSCM HIGHTEC BJLAND JCBNEXT DAYA...
58   2016-01-31  GPHAROS NGGB MYSCM HIGHTEC BJLAND JCBNEXT DAYA...
59   2016-02-29  EMETALL SKBSHUT GETS HIGHTEC BJLAND EFFICEN RO...
60   2016-03-31  EMETALL SKBSHUT GETS SAPIND EFFICEN JKGLAND RO...
61   2016-04-30  EMETALL SKBSHUT REACH SAPIND EFFICEN JKGLAND R...
62   2016-05-31  DRBHCOM REACH SAPIND PARAGON MTRONIC KPS NPC K...
63   2016-06-30  SUBUR DRBHCOM REACH PARAGON MTRONIC KPS JKGLAN...
64   2016-07-31  SUBUR DRBHCOM REACH PARAGON MTRONIC KPS JKGLAN...
65   2016-08-31  SUBUR YKGI ZECON LIONPSIM LBICAP ANNJOO REACH ...
66   2016-09-30  TECGUAN YKGI ZECON LIONPSIM LBICAP ANNJOO REAC...
67   2016-10-31  TECGUAN YKGI ZECON LIONPSIM LBICAP ANNJOO REAC...
68   2016-11-30  TECGUAN EMICO PHB REACH BJASSET ATTA SMCAP KOM...
69   2016-12-31  EMICO PHB REACH ATTA SMCAP GPA BSLCORP CWG LAY...
70   2017-01-31  EMICO HIGHTEC PHB REACH ATTA SMCAP GPA CWG LAY...
71   2017-02-28  CNASIA HIGHTEC UMW MIECO LIONIND SUCCESS REACH...
72   2017-03-31  CNASIA UMW MIECO LIONIND SUCCESS EDEN EMICO ME...
73   2017-04-30  POLY CNASIA UMW MIECO LIONIND EDEN EMICO GUOCO...
74   2017-05-31  POLY ATAIMS BINTAI ACME BJASSET TIGER EATECH G...
75   2017-06-30  POLY ATAIMS BINTAI ACME BJASSET TIGER EATECH G...
76   2017-07-31  ATAIMS BINTAI ACME BJASSET TIGER EATECH GUOCO ...
77   2017-08-31  GRANFLO HUAAN LEWEKO MG LIONPSIM ZECON DWL BAR...
78   2017-09-30  GRANFLO HUAAN LEWEKO MG ZECON DWL BARAKAH MEDI...
79   2017-10-31  GRANFLO LEWEKO HUAAN MG ZECON DWL BARAKAH MEDI...
80   2017-11-30  MULPHA LIONPSIM HARNLEN HUAAN STAR TOYOINK HAR...
81   2017-12-31  MULPHA LIONPSIM HARNLEN HUAAN STAR TOYOINK BPL...
82   2018-01-31  MULPHA LIONPSIM HARNLEN HUAAN STAR TOYOINK BPL...
83   2018-02-28  PRKCORP AMPROP TPC JAKS DBE ALAM TOYOINK WATTA...
84   2018-03-31  PRKCORP SAPNRG AMPROP TPC JAKS DBE ALAM TOYOIN...
85   2018-04-30  PRKCORP SAPNRG AMPROP TPC JAKS DBE ALAM TOYOIN...
86   2018-05-31  SAPNRG HUMEIND OLYMPIA ARREIT JKGLAND ASIAPAC ...
87   2018-06-30  GUOCO MUDA HUMEIND OLYMPIA ARREIT ASIAPAC GUNU...
88   2018-07-31  MUDA HUMEIND OLYMPIA CCB ARREIT ASIAPAC GUNUNG...
89   2018-08-31  COASTAL AXIATA TIGER PEB CCB HTPADU VERTICE EA...
90   2018-09-30  COASTAL AXIATA TIGER PEB CCB HTPADU VERTICE EA...
91   2018-10-31  COASTAL WZSATU AXIATA TIGER PEB CCB AJIYA HTPA...
92   2018-11-30  FGV WZSATU PCCS FLBHD TADMAX ENGKAH AJIYA SWKP...
93   2018-12-31  FGV WZSATU UZMA PCCS FLBHD TADMAX ENGKAH AJIYA...
94   2019-01-31  FGV PCCS FLBHD TADMAX PJBUMI CVIEW SWKPLNT ITR...
95   2019-02-28  THPLANT DBHD ARBB CHUAN HWGB MAYBULK ADVENTA A...
96   2019-03-31  THPLANT DBHD ARBB CHUAN HWGB MAYBULK ADVENTA A...
97   2019-04-30  THPLANT DBHD CHUAN HWGB MAYBULK ADVENTA ARK IP...
98   2019-05-31  HENGYUAN SEB HBGLOB IJMPLNT ARBB MULPHA ASIAPA...
99   2019-06-30  HENGYUAN SEB HBGLOB IJMPLNT ARBB MULPHA ASIAPA...
100  2019-07-31  HENGYUAN SEB HBGLOB IJMPLNT ARBB MULPHA ASIAPA...
101  2019-08-31  DOLMITE PMCORP HENGYUAN ENGKAH PRESBHD ENGTEX ...
102  2019-09-30  DOLMITE PMCORP HENGYUAN ENGKAH PRESBHD ENGTEX ...
103  2019-10-31  DOLMITE PMCORP HENGYUAN ENGKAH PRESBHD ENGTEX ...
104  2019-11-30  FGV KHEESAN DBE DAYANG BONIA NAIM MJPERAK PINE...
105  2019-12-31  SCNWOLF FGV KHEESAN DBE DAYANG NAIM MJPERAK PI...
106  2020-01-31  SCNWOLF FGV KHEESAN DBE NAIM MJPERAK PINEPAC S...
107  2020-02-29  HARBOUR OWG ILB DPS KUB KHEESAN BSTEAD PARAGON...
108  2020-03-31  HARBOUR OWG ILB DPS KUB BSTEAD PARAGON TIGER G...
109  2020-04-30  HARBOUR OWG ILB DPS KUB PENSONI BSTEAD PARAGON...
110  2020-05-31  HARBOUR OWG ILB CNASIA DPS MAYBULK KHIND PENSO...
111  2020-06-30  SMISCOR CNASIA MAYBULK KHIND PENSONI COMPLET A...
112  2020-07-31  SMISCOR CNASIA TAS MAYBULK NYLEX KHIND KPPROP ...
113  2020-08-31  IMPIANA ALLIANZ JERASIA STAR TAS BJASSET TCHON...
114  2020-09-30  SEACERA ALLIANZ JERASIA STAR TAS BJASSET TCHON...
115  2020-10-31  SEACERA ALLIANZ JERASIA STAR BJASSET TCHONG MS...
116  2020-11-30  SWSCAP DBE JERASIA MSC CNI HARNLEN DPS TSRCAP ...
117  2020-12-31  SWSCAP DBE MBSB MSC CNI HARNLEN DPS TRC SIMEPR...
118  2021-01-31  SWSCAP DBE MBSB EUPE MSC CNI HARNLEN DPS PENER...
119  2021-02-28  DBE SWSCAP GMUTUAL AYS LATITUD PPG MRCB ITRONI...
120  2021-03-31  DBE PRKCORP AYS LATITUD MJPERAK PPG MRCB ITRON...
121  2021-04-30  DBE PRKCORP AYS LATITUD MJPERAK PPG MRCB SASBA...
122  2021-05-31  PRKCORP AYS PPG MJPERAK MRCB SASBADI IJMPLNT I...
123  2021-06-30  AYS PPG SASBADI BREM COASTAL MHB YTL ICON TITI...
124  2021-07-31  AYS BREM COASTAL YTL ICON TITIJYA AMEDIA CYMAO...
125  2021-08-31  GLBHD COASTAL BHIC SCABLE SHCHAN YTL EMETALL A...
126  2021-09-30  PRTASCO GLBHD AAX MPCORP MTRONIC BHIC SCABLE S...
127  2021-10-31  PRTASCO GLBHD AAX MPCORP MTRONIC BHIC SCABLE S...

黄金法则的资金增长

有了选好的公司,现在就来计算资金的增长

maxreturn = output['Average gains'].max()
if math.isnan(maxreturn):
    maxreturn = 0

win = output[output['Average gains']>=100].shape[0]
total = output.shape[0]
print('Maximum return  : ' + str(maxreturn))
print('Maximum retreat : ' + str(output['Average gains'].min()))
print('Average return  : ' + str(output['Average gains'].median()))
print('CAGR            : ' + str(CompoundedGrowth))
print('Winrate         : ' + str(float(win)/float(total)))

fig, axs = plt.subplots(2,1)
output.plot.line(y='Capital', subplots=True, ax = axs[0], color = 'Green', label = 'KYY')
output.plot.line(y='Benchmark', subplots=True, ax = axs[0], color = 'Blue', label = 'KLCI')

# axs[0].set_yscale('log')
output.plot.line(y='Average gains', subplots=True, ax = axs[1])
plt.legend(loc='upper right')
plt.show()
Maximum return  : 145.3678663108833
Maximum retreat : 78.13646022905483
Average return  : 101.15013712494064
CAGR            : 21.124786717204923
Winrate         : 0.5859375

结论

  • 官老前辈的黄金法则有不错的成绩,21% 复合年增长58% 的赢率
  • 回测结构显示资金在10年内从RM1000增长到RM8000
  • 文章内的选股方法是非常机械性的,官老前辈可能会灵活地使用他的黄金法则,不过这篇文章可以大概研究黄金法则的绩效

纯属分享,无买卖建议

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Verified by MonsterInsights