klsequant

klsequant | 用数据告诉你均线策略在马股的有效性

klsequant
Publish date: Mon, 24 May 2021, 11:14 AM

用数据告诉你均线策略在马股的有效性

均线策略

移动均线算是交易者们最常用的指标之一。

因为它在各大网站或图标软件都能见到它的踪影。

一个非常常用的策略就是金叉/死叉策略,

快线穿过慢线时买入,

快线跌破慢线时卖出。

这篇文章我们来探讨这个策略在马股KLSE指数的表现如何。

数据读取

我从Yahoo Finance上下载了KLSE指数的历史数据,

要分析数据得先读取这个csv文件。

1
2
3
4
5
6
7
8
9
import pandas as pd

KLSE = pd.read_csv('KLSE.csv')
KLSE = KLSE.replace(',','', regex=True)
KLSE['Open'] = KLSE['Open'].astype(float)
KLSE['Close'] = KLSE['Close'].astype(float)
KLSE['Change'] = (KLSE['Close'] - KLSE['Close'].shift(1))/KLSE['Open'] + 1

KLSE.head()
  Date Open High Low Close Adj Close Volume
0 4-Jan-10 1272.31 1275.75 1272.25 1275.75 1275.75 56508200
1 5-Jan-10 1278.26 1290.55 1278.26 1288.24 1288.24 136646600
2 6-Jan-10 1288.86 1296.44 1288.02 1293.17 1293.17 117740300
3 7-Jan-10 1293.69 1299.70 1290.36 1291.42 1291.42 115024400
4 8-Jan-10 1294.93 1295.51 1290.86 1292.98 1292.98 74587200

策略规则

我们以最简单的双均线策略进行回测,

具体规则:

  1. 快线穿过慢线时买入
  2. 快线跌破慢线时卖出
  3. 不考虑交易成本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def simulate(df,fast,slow):
    
    import talib

    df['fast'] = talib.SMA(df['Close'],fast)
    df['slow'] = talib.SMA(df['Close'],slow)
    
    df.dropna(inplace = True)

    gold_cross = df[df['fast'] > df['slow']].index
    df.loc[gold_cross,'Cross'] = 1

    gold_cross = df[df['fast'] < df['slow']].index
    df.loc[gold_cross,'Cross'] = 0

    df['Buy'] = df['Cross'].diff()

    df['Return'] = df['Cross']*df['Change']

    def norm(x):
        if x == 0:
            return 1
        else:
            return x

    df['Return'] = df['Return'].apply(lambda x: norm(x))
    df['Nav'] = (df['Return']).cumprod()

    price_in = df.loc[df['Buy'] == 1,'Close'].values
    price_out = df.loc[df['Buy'] == -1,'Close'].values

    # divide by 252 because generally a year has 252 trading days
    num_periods = df.shape[0]/252
    rety = ((df['Nav'].iloc[-1] / df['Nav'].iloc[0]) ** (1 / (num_periods - 1)) - 1)*100.0

    if len(price_out) > len(price_in):
        price_out = price_out[:len(price_in)]
    
    if len(price_in) > len(price_out):
        price_in = price_in[:len(price_out)]
        
    VictoryRatio = ((price_out - price_in)>0).mean()*100.0
    DD = 1 - df['Nav']/df['Nav'].cummax()
    MDD = max(DD)*100.0

    return df, round(rety, 2), round(VictoryRatio, 2), round(MDD,2)

策略表现

我们测试3对的均线,

毕竟每个人都会有自己喜欢的均线组合

  1. 10天线 和 20天线 (短期交易)
  2. 20天线 和 50天线 (中期交易)
  3. 50天线 和 200天线 (长期交易)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
MA1020,cagr1020,vr1020,mdd1020 = simulate(KLSE.copy(),10,20)
MA2050,cagr2050,vr2050,mdd2050 = simulate(KLSE.copy(),20,50)
MA50200,cagr50200,vr50200,mdd50200 = simulate(KLSE.copy(),50,200)

KLSE['KLSE'] = (KLSE['Change']).cumprod()
import matplotlib.pyplot as plt
plt.style.use('seaborn')

ax = MA1020['Nav'].plot(figsize=(10, 6))
MA2050['Nav'].plot(ax=ax)
MA50200['Nav'].plot(ax=ax)
KLSE['KLSE'].plot(ax=ax)
# plt.plot( 'Date','Nav', data = MA2050, marker='', color='olive', linewidth=2)
ax.legend(['MA1020','MA2050','MA50200','KLSE']);
plt.show()


from prettytable import PrettyTable

t = PrettyTable(['Strategy', 'CAGR', 'Win Rate', 'Max Drawdown'])
t.add_row(['MA1020', cagr1020,vr1020,mdd1020])
t.add_row(['MA2050', cagr2050,vr2050,mdd2050])
t.add_row(['MA50200', cagr50200,vr50200,mdd50200])

print(t)

png

+----------+-------+----------+--------------+
| Strategy |  CAGR | Win Rate | Max Drawdown |
+----------+-------+----------+--------------+
|  MA1020  |  6.44 |  50.77   |     8.52     |
|  MA2050  |  3.14 |  30.77   |    12.15     |
| MA50200  | -0.89 |  28.57   |    30.08     |
+----------+-------+----------+--------------+

想法

从数据来看,看来短期的策略最适合KLSE指数

它的赢率也是最高的。

而且也大幅跑赢KLSE指数。

较长期的均线组合的表现较差强人意,

有些表现还不如直接买入持有。

这可能是因为KLSE指数的长期走势不强,

如果把这策略套用在长期走势强劲的指数(比如SP500),

相信成绩会好看得多。

想要自己测试的读者可以从Yahoo Finance下载想要的个股数据来分析看看。

纯属分享,无买卖建议

 

欢迎follow我们的fb https://www.facebook.com/klsequant

Discussions
Be the first to like this. Showing 0 of 0 comments

Post a Comment