交易策略-MACD买卖跟踪

博主: Simon Lin 创建于: Mar 16, 2019 更新于: Mar 16, 2019
分类: stock
标签: finance stock macd

策略要解决的问题

这是我分享的第一个应用于模拟交易的策略。
一个自动化的交易体系,需要解决几个问题。

  1. 选什么股票
  2. 什么时候买,买多少
  3. 什么时候卖,卖多少

问题有点多啊,那么就先简化一些,手工选几个蓝筹股先,让算法来算出什么时候买卖,买多少的问题,先根据资金均分,卖多少先不处理,卖空就是。

策略的思路

前文有说过,我曾做过一个自定义的趋势类的指标,问题是引入了未来的数据,导致无法用在模拟交易上。那么仔细考虑了一下,MACD并没有引入未来数据,而且给出信号的频率和趋势指标非常的接近,可以用MACD来进行买入卖出点的判断。前文也提到过,趋势指标给的信号会比MACD的信号快一些,那么我们就对MACD给的信号做一些变化,更早的给出信号,就可以接近自定义趋势指标的信号了。什么时候买,什么时候卖的问题也就基本解决了。

如上图,这是一个沪深300的自定义趋势指标和MACD交叉指标,趋势信号给出的时候,macd要延后几天,最简单的方法就是,macd指标给出信号,不再是与0进行交叉的时候,大约小于17的时候给出信号,就能提早了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#MACD具体计算:
#Dif 即MACD;Dea即MACDsignal;Dea-Dif=Macdhist
#快速线为DIF,慢速线为DEA,柱状图为MACD(Macdhist)
#手机软件上的macd即(Dea-Dif)*2
def get_MACD(sc=None,end_date=None,start_date=None,count=0,df = None):
if not df is None:
dm = df
elif count==0:
df=get_price(frequency='daily',fields=['open','close','volume'], security=sc, skip_paused=False, fq='pre',start_date=start_date,end_date=end_date)
else:
df=get_price(frequency='daily',fields=['open','close','volume'], security=sc, skip_paused=False, fq='pre',count=count,end_date=end_date)

close = [float(x) for x in df['close']]

# 调用talib计算MACD指标
df['MACD'],df['MACDsignal'],df['MACDhist'] = talib.MACD(np.array(close),
fastperiod=12, slowperiod=26, signalperiod=9)
dr=copy.deepcopy(df[['MACD','MACDsignal','MACDhist']])
return dr

根据以上的分析,我制作了一个这样的简单逻辑,具体核心代码就如下,就是对于何时给出信号修改了判断逻辑。
算法上,主要就是改进了MACD比较慢的问题,太慢就会丧失很大的收益,所以不再采用MACD柱穿过0轴的方式来定义买入卖出点,而采用更为激进的门限,MACD柱穿过门限即触发买入卖出。如果门限是0,所有的股票都可以通用,可如果不是0,这个门线的计算就会发生一个问题,看指数的MACD柱经常是两位数,而单价小于5的股票,MACD柱也会是很小。在这里有一个具体门限计算的逻辑,分析了MACD数值的算法,简单化的采用30日左右的均线去除一个固定值来作为门限。具体的门限标准是这个买入卖出点与自定义趋势指标进行对比,尽量靠近趋势变化的点,通过这个方法来尝试定义门限。
从简单的对比上,就可以发现,这个卖出信号被提前了,而且非常有效。

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
def get_MACDext(df):
macd = get_MACD(df=df)

macd['macd1'] = macd['MACDhist']
macd['macd2'] = macd['MACDhist'].shift(1)

limit = macd.index.map(lambda x:get_ma30_price(df=df,check_date=x)/240)

signallist = pd.Series(0, index=macd.index)
limitlist = pd.Series(limit, index=macd.index)
macd['limit']=limitlist
for index, row in macd.iterrows():
if row['macd2']>row['limit'] and row['macd1']<row['limit']:
signallist[index] = -2 #瞬时卖出信号
elif row['macd2']<-1*row['limit'] and row['macd1']>-1*row['limit']:
signallist[index] = 2 #瞬时买入信号
elif row['macd2']<-1*row['limit'] and row['macd1']<-1*row['limit']:
signallist[index] = -1 #持续卖出信号
elif row['macd2']>row['limit'] and row['macd1']>row['limit']:
signallist[index] = 1 #持续买入信号
else:
signallist[index] = 0

macd['signal']=signallist
return macd

策略回测


10年回测的成绩还是不错的,年化可以到13%的收益率,买入卖出点判断的胜率大约可以是0.448,而胜利时利润更高些,有亏损时有及时的止损。特别看一下,2017年1月2日的收益时116%,到2019年2月初229%,年化收益接近25%,而同期沪深300的收益为负。

实战

我已经将此策略进行实际盘面的模拟交易,从2019年2月开始模拟,至今3月14日的一个月左右成绩收益率10.79%
https://www.joinquant.com/post/16631

所谓吃鱼吃整条,之前用模拟交易的方式设计了macd跟踪算法,这里就来看下实战的效果。从2月14日买入9.81共3000股32373元投入,3月13日13.73全部卖出,收回45309,收益约30%。

从图形上看,基本上从最低点一直持有到了最高点才抛出,吃到了这个月收益中最丰盛的一段。我本人也是实际买入了振芯科技,一直持有到了2月26日抛出的,少吃了一个涨停板,没有模拟交易这么大的收益。这里我想说的是执行力,制定的策略一定要坚决执行。止盈要坚决执行之前的策略,止损更要坚决。这个就是一个非常好的教训。

3月15日,模拟盘买入中国平安73.19元,过一段时间再来分享下这个股票是否成功挣到钱。

PS. 此策略算法,其实手工在MACD图上也可以人工做,进行买入卖出的判断,当然,实际算法中我加入了一定的止损止盈方案等,有兴趣的可以私信我。


打赏 支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者