交易者必须自律,这是一个身为投资者/交易者时常听见的话
每笔交易都要有进场出场与止损的计划
止损是一种风险管理工具,目的让你能结束交易来防止更多的亏损
今天我们就来研究看看止损到底是不是有效的方法
至于止损该设多少,每个交易者都不同
常见的有5% 10%,这也得考虑你的风险偏好
数据读取
我从Yahoo Finance上下载了KLSE指数的历史数据,
要分析数据得先读取这个csv文件。
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 | Change | |
---|---|---|---|---|---|---|---|---|
0 | 4-Jan-10 | 1272.31 | 1275.75 | 1272.25 | 1275.75 | 1275.75 | 56508200 | NaN |
1 | 5-Jan-10 | 1278.26 | 1290.55 | 1278.26 | 1288.24 | 1288.24 | 136646600 | 1.009771 |
2 | 6-Jan-10 | 1288.86 | 1296.44 | 1288.02 | 1293.17 | 1293.17 | 117740300 | 1.003825 |
3 | 7-Jan-10 | 1293.69 | 1299.70 | 1290.36 | 1291.42 | 1291.42 | 115024400 | 0.998647 |
4 | 8-Jan-10 | 1294.93 | 1295.51 | 1290.86 | 1292.98 | 1292.98 | 74587200 | 1.001205 |
策略规则
我们以最简单的双均线策略 + 5% 止损进行回测,
具体规则:
- 快线穿过慢线时买入
- 快线跌破慢线时卖出
- 账面亏损大于 5% 就卖出
- 不考虑交易成本
def simulate(df,fast,slow,cutloss = False):
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()
DD = 1 - df['Nav']/df['Nav'].cummax()
#===================================
if cutloss:
# set cutloss to 5.5% for extra buffer
c = DD[DD > 0.055].index
df.loc[c,'Cross'] = 0
df['Buy'] = df['Cross'].diff()
df['Return'] = df['Cross']*df['Change']
df['Return'] = df['Return'].apply(lambda x: norm(x))
df['Nav'] = (df['Return']).cumprod()
#====================================
# 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
price_in = df.loc[df['Buy'] == 1,'Close'].values
price_out = df.loc[df['Buy'] == -1,'Close'].values
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)
策略表现
我们测试4个组合的策略,
- 10天线 和 20天线 (短期交易),无止损
- 20天线 和 50天线 (中期交易),无止损
- 10天线 和 20天线 (短期交易),5%止损
- 20天线 和 50天线 (中期交易),5%止损
MA1020,cagr1020,vr1020,mdd1020 = simulate(KLSE.copy(),10,20,False)
MA2050,cagr2050,vr2050,mdd2050 = simulate(KLSE.copy(),20,50,False)
MA1020_cutloss,cagr1020_cutloss,vr1020_cutloss,mdd1020_cutloss = simulate(KLSE.copy(),10,20,True)
MA2050_cutloss,cagr2050_cutloss,vr2050_cutloss,mdd2050_cutloss = simulate(KLSE.copy(),20,50,True)
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)
MA1020_cutloss['Nav'].plot(ax=ax)
MA2050_cutloss['Nav'].plot(ax=ax)
KLSE['KLSE'].plot(ax=ax)
# plt.plot( 'Date','Nav', data = MA2050, marker='', color='olive', linewidth=2)
ax.legend(['MA1020','MA2050','MA1020 5% Cutloss','MA2050 5% Cutloss','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(['MA1020 5% Cutloss', cagr1020_cutloss,vr1020_cutloss,mdd1020_cutloss])
t.add_row(['MA2050 5% Cutloss', cagr2050_cutloss,vr2050_cutloss,mdd2050_cutloss])
print(t)
+-------------------+------+----------+--------------+
| Strategy | CAGR | Win Rate | Max Drawdown |
+-------------------+------+----------+--------------+
| MA1020 | 6.44 | 50.77 | 8.52 |
| MA2050 | 3.14 | 30.77 | 12.15 |
| MA1020 5% Cutloss | 7.19 | 45.21 | 5.44 |
| MA2050 5% Cutloss | 4.54 | 20.59 | 5.46 |
+-------------------+------+----------+--------------+
想法
从回测结果看来,
止损看起来是有效的风险管理技巧
设下5%止损的策略都比无止损的策略来的好
虽然赢率(Win Rate)较低
这可能是有止损的会更常认赔出局,这也可以说是好事
想要自己测试的读者可以从Yahoo Finance下载想要的个股数据来分析看看。
纯属分享,无买卖建议