股票量化分析(11)——第二个策略(5日移动均线、双均线、MACD策略)

本文通过使用talib库实现并比较了三种不同的股票交易策略:移动均线策略、双均线策略及MACD策略。结果显示,MACD策略能有效规避市场大幅波动,尽管收益提升空间仍待进一步优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里主要用的是talib这个库来求股票的指标,就免得造轮子。
移动均线有好几个策略,不过都是简单的策略,包括简单的移动均线策略,双均线交叉策略,macd线的策略。目前也就觉得macd线简单好用。

先放一个简单的策略——移动均线策略。这个策略是由下向上超过均线就买入,相反就卖出,最后会发现这个策略没什么卵用,明显低于股票自身的累计收益,不过方法可以参考一下。

import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import talib

df=ts.get_hist_data('600848',start='2015-01-01',end='2015-12-31')
df=df.sort_index()
df.index=pd.to_datetime(df.index,format='%Y-%m-%d')
#收市股价
close= df.close
#每天的股价变动百分率
ret=df.p_change/100
# 10日的移动均线为目标
df['SMA_10'] = talib.MA(np.array(close), timeperiod=10)
close10=df.SMA_10

#处理信号
SmaSignal=pd.Series(0,index=close.index)

for i in range(10,len(close)):
    if all([close[i]>close10[i],close[i-1]<close10[i-1]]):
        SmaSignal[i]=1
    elif all([close[i]<close10[i],close[i-1]>close10[i-1]]):
        SmaSignal[i]=-1

SmaTrade=SmaSignal.shift(1).dropna()

SmaBuy=SmaTrade[SmaTrade==1]

SmaSell=SmaTrade[SmaTrade==-1]

SmaRet=ret*SmaTrade.dropna()

#累积收益表现
#股票累积收益率
cumStock=np.cumprod(1+ret[SmaRet.index[0]:])-1
#策略累积收益率
cumTrade=np.cumprod(1+SmaRet)-1
plt.rcParams['font.sans-serif']=['SimHei']
plt.plot(cumStock,label="cumStock",color='k')
plt.plot(cumTrade,label="cumTrade",color='r',linestyle=':')
plt.title("股票累积收益率与10日平均策略收益率")
plt.legend()

这里写图片描述

双均线策略:即5日短线移动平均超过30日长线移动平均即买入,其余时候空仓。

import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import talib

df=ts.get_hist_data('600848',start='2015-01-01',end='2015-12-31')
df=df.sort_index()
df.index=pd.to_datetime(df.index,format='%Y-%m-%d')
#收市股价
close= df.close
#每天的股价变动百分率
ret=df.p_change/100
# 5\30日的移动均线为目标
df['SMA_5'] = talib.MA(np.array(close), timeperiod=5)
df['SMA_30'] = talib.MA(np.array(close), timeperiod=30)
close5=df.SMA_5
close30=df.SMA_30

#处理信号
SmaSignal=pd.Series(0,index=close.index)

for i in range(10,len(close)):
    if all([close5[i]>close30[i]]):
        SmaSignal[i]=1


SmaTrade=SmaSignal.shift(1).dropna()

SmaRet=ret*SmaTrade.dropna()

#累积收益表现
#股票累积收益率
cumStock=np.cumprod(1+ret[SmaRet.index[0]:])-1
#策略累积收益率
cumTrade=np.cumprod(1+SmaRet)-1
plt.rcParams['font.sans-serif']=['SimHei']
plt.plot(cumStock,label="cumStock",color='k')
plt.plot(cumTrade,label="cumTrade",color='r',linestyle=':')
plt.title("股票累积收益率与双均线策略收益率")
plt.legend()

这里写图片描述

结果发现大部分时候双均线交易策略的收益小于股票本身的累计收益。

下面看看MACD交易策略:即DIFF大于DEA的时候买入,其他时候卖出。

import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import talib

df=ts.get_hist_data('600848',start='2015-01-01',end='2015-12-31')
df=df.sort_index()
df.index=pd.to_datetime(df.index,format='%Y-%m-%d')
#收市股价
close= df.close
#每天的股价变动百分率
ret=df.p_change/100
 # 调用talib计算MACD指标
df['DIFF'],df['DEA'],df['MACD'] = talib.MACD(np.array(close),
                            fastperiod=12, slowperiod=26, signalperiod=9)


diff=df.DIFF
dea=df.DEA

#处理信号
macdSignal=pd.Series(0,index=close.index)

for i in range(10,len(close)):
    #if all([diff[i]>dea[i]>0,diff[i-1]<dea[i-1]]):
    if all([diff[i]>dea[i]]):
        macdSignal[i]=1
    #elif all([diff[i]<dea[i]<0,diff[i-1]>dea[i-1]]):
        #macdSignal[i]=-1


macdTrade=macdSignal.shift(1).dropna()
macdRet=ret*macdTrade.dropna()

#累积收益表现
#股票累积收益率
cumStock=np.cumprod(1+ret[macdRet.index[0]:])-1
#策略累积收益率
cumTrade=np.cumprod(1+macdRet)-1
plt.rcParams['font.sans-serif']=['SimHei']
plt.plot(cumStock,label="cumStock",color='k')
plt.plot(cumTrade,label="cumTrade",color='r',linestyle=':')
plt.title("股票累积收益率与macd策略收益率")
plt.legend()

这里写图片描述
从图中可以看出,macd策略成功躲避了暴涨暴跌,但最后收益稍微好于双移动均线,如果能够继续优化一下,能够避免那个波谷阶段的暴跌,收益还是很可观的,这就需要继续优化策略。所以学习量化分析能够让你冷静的看待自己的交易策略,并不断优化它。

<think>我们正在使用Pybroker构建一个股票量化交易策略模型。策略要求:1.60和120均线多头排列(即60均线在120均线上方)且当前价格在60均线上方。2.一周前(即5个交易之前)MACD0轴下方出现金叉(即MACD线由下向上穿越信号线,且此时MACD值小于0)。步骤:1.定义策略条件:我们需要计算每只股票的60均线(ma60)、120均线(ma120)以及MACD指标(包括MACD线和信号线)。2.多头排列条件:ma60>ma120,并且当前收盘价(close)大于ma60。3.MACD金叉条件:在5个交易前,MACD线(macd_line)上穿信号线(signal_line),并且当时MACD值(即macd_line)小于0。注意:在Pybroker中,我们可以使用`indicator`来计算技术指标,然后在策略中使用`when`来触发交易信号。首先,我们需要计算MACD指标。MACD通常由三部分组成:MACD线(DIF)、信号线(DEA)和柱状图(MACDHistogram)。这里我们关注DIF和DEA。MACD的计算公式如下:-快速EMA(一般取12):EMA(close,12)-慢速EMA(一般取26):EMA(close,26)-DIF=快速EMA-慢速EMA-DEA(信号线)=DIF的9EMA金叉:当DIF从下向上穿越DEA时,形成金叉。由于策略要求一周前(5个交易)出现金叉,因此我们需要在5天前的位置检查条件。在Pybroker中,我们可以使用`shift(n)`来获取n天前的数据。接下来,我们将按照以下步骤编写策略:1.使用`@indicator`装饰器计算移动均线MACD指标。2.在策略函数中,使用`when`装饰器定义买入信号条件。注意:Pybroker在回测时会按时间顺序处理每个交易的数据,因此我们可以安全地使用过去的数据(通过`shift`)。具体实现:首先,计算60和120均线:```pythonfrompybrokerimportStrategy,StrategyConfig,YFinance,Indicator,setup_configimportnumpyasnp#设置配置setup_config(enable_caching=True)#启用缓存加快回测速度#定义指标defcalc_ma(df,*args):#df是一个包含期和股票数据的DataFrameforninargs:df[f'ma{n}']=df['close'].rolling(window=n).mean()#计算MACDdefcalc_macd(df):#计算12和26的EMAema12=df['close'].ewm(span=12,adjust=False).mean()ema26=df['close'].ewm(span=26,adjust=False).mean()df['dif']=ema12-ema26df['dea']=df['dif'].ewm(span=9,adjust=False).mean()#为了判断金叉死叉,我们可以计算交叉点#我们也可以直接通过比较当前和前一天的DIF和DEA来判断交叉#注意:在Pybroker中,我们使用Indicator来添加自定义指标Indicator('ma',calc_ma,args=(60,120))#这样会计算出ma60和ma120Indicator('macd',calc_macd)```然后,编写策略:```pythondefbuy_signal(ctx):#获取当前股票的数据symbol=ctx.symboldate=ctx.date#获取当前和过去的数据#注意:ctx.bars是当前股票的历史数据,包括我们计算的指标#我们使用ctx.bars的长度和当前索引位置来获取5天前的数据#但更方便的是,我们可以使用shift方法在指标计算时已经将历史数据包含在DataFrame中#因此,我们可以直接通过列名和.shift(5)来获取5天前的值#获取当前和5天前的MACD值#当前数据:ctx.bars[-1]是最后一个bar(即当前交易)#由于我们的指标已经计算在DataFrame中,所以我们可以通过列名访问#但是注意:在策略函数中,我们只能访问到当前交易的数据(通过ctx)和之前缓存的数据(通过ctx.indicator)#因此,我们需要在指标计算时就将历史数据包含在DataFrame中,然后在策略中通过.shift来访问过去的数据#在策略中,我们可以这样获取指标值:ma60=ctx.indicator('ma60')#当前ma60ma120=ctx.indicator('ma120')#当前ma120close=ctx.close#当前收盘价#多头排列条件:ma60>ma120andclose>ma60cond1=(ma60>ma120)and(close>ma60)#获取5天前的MACD指标#注意:ctx.indicator返回的是当前的值,我们需要过去的值,所以使用ctx.indicator_data#但是Pybroker提供了`shift`方法吗?在策略函数中,我们可以通过缓存的数据来获取历史值。#我们可以使用`ctx.prev(n)`来获取n天前的指标值,但是注意:n不能超过缓存的大小(默认是1000)#我们使用ctx.prev(n)来获取n天前的指标数据#获取5天前的dif和deaprev_dif=ctx.prev('dif',5)#5天前的dif值prev_dea=ctx.prev('dea',5)#5天前的dea值#还需要获取4天前的dif和dea(因为金叉需要前一天和当天比较)prev_dif_1=ctx.prev('dif',4)#4天前(即前一天)的difprev_dea_1=ctx.prev('dea',4)#4天前的dea#注意:金叉条件:5天前(也就是我们观察的那天)的dif上穿dea,即:#4天前(前一天):dif<=dea,然后5天前(当天):dif>dea#同时,要求5天前的dif<0(因为金叉发生在0轴下方)cond2=(prev_dif_1<=prev_dea_1)and(prev_dif>prev_dea)and(prev_dif<0)#注意:这里我们观察的是5天前(即一周前)出现金叉,然后我们当前交易买入#因此,我们只需要在满足当前均线多头排列且一周前有金叉时买入ifcond1andcond2:#买入信号ctx.buy_shares=100#假设买入100股#或者使用固定金额买入,例如:ctx.buy_value=10000#买入10000美元```然后,我们需要将策略组合起来:```python#创建策略strategy=Strategy(YFinance(),start_date='2020-01-01',end_date='2023-01-01')strategy.add_execution(buy_signal,['AAPL','MSFT'])#可以添加多个股票代码#运行回测result=strategy.backtest(initial_cash=100000)```注意:以上代码是示例,可能需要根据实际情况调整。特别是:-确保数据源(YFinance)能够获取到所需的股票数据。-指标计算中,我们使用了`rolling`和`ewm`,注意窗口大小和数据长度。-MACD的金叉判断:我们通过比较前一天和当天来判断交叉,注意我们这里用5天前和4天前(因为5天前是目标,4天前是目标的前一天)。但是注意,在回测时,我们处理的是当前交易,而5天前是指当前交易往前推5个交易。所以,在回测中,我们能够获取到历史数据。另外,由于我们使用了`ctx.prev(n)`,所以需要确保在策略配置中缓存足够的数据(默认是1000个交易,足够)。最后,我们还需要考虑卖出条件。但是问题中没有给出卖出条件,所以我们可以设定一个简单的卖出条件,比如持有5天后卖出,或者设定止损止盈。这里为了完整,我们可以添加一个持有5天后卖出的条件。```pythondefsell_signal(ctx):#获取持仓信息position=ctx.long_pos()ifposition:#如果有持仓#获取持仓天数hold_days=ctx.bar_index-position.bar_indexifhold_days>=5:#持有5天后卖出ctx.sell_shares=position.shares#卖出所有持仓```然后,在策略中添加这个执行函数:```pythonstrategy.add_execution(sell_signal,['AAPL','MSFT'])```但是注意:同一个股票不能同时有两个执行函数,所以我们可以将买入和卖出写在同一个执行函数中,或者分别添加。Pybroker允许同一个策略添加多个执行函数,它们会按添加顺序执行。因此,完整的策略代码可能如下:```pythonfrompybrokerimportStrategy,StrategyConfig,YFinance,Indicator,setup_configsetup_config(enable_caching=True)#定义计算均线的指标defcalc_ma(df,*args):forninargs:df[f'ma{n}']=df['close'].rolling(window=n).mean()#定义计算MACD的指标defcalc_macd(df):ema12=df['close'].ewm(span=12,adjust=False).mean()ema26=df['close'].ewm(span=26,adjust=False).mean()df['dif']=ema12-ema26df['dea']=df['dif'].ewm(span=9,adjust=False).mean()#注册指标Indicator('ma',calc_ma,args=(60,120))Indicator('macd',calc_macd)#策略执行函数defexecute(ctx):#买入信号ma60=ctx.indicator('ma60')ma120=ctx.indicator('ma120')close=ctx.closecond1=(ma60>ma120)and(close>ma60)#获取5天前的MACD相关值#注意:我们这里需要5天前的数据和4天前的数据(5天前的前一天)prev_dif=ctx.prev('dif',5)#5天前的difprev_dea=ctx.prev('dea',5)#5天前的deaprev_dif_1=ctx.prev('dif',4)#4天前的dif(即5天前的后一天,但这里我们取的是相对于当前5天前,那么4天前就是5天前的下一个交易?注意:时间顺序)#但是注意:ctx.prev(n)返回的是n个交易之前的数据。所以,当前交易是t,那么:#n=0:t#n=1:t-1#n=2:t-2#...#n=5:t-5#n=4:t-4#所以,对于5天前
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值