名词解释
均线MA(N)
N日平均线的平均数 MA(N)=(C1+C2+C3+..)/N
MA就是一般的平均,一段时间内所有值加起来再除以该段时间内的值的个数
指数平滑移动平均线EMA(N)
EMA(N)=2/(n+1)*(今日收盘价-昨日EMA)
EMA是加权平均,可以理解为越近期的值越被重视,越早期的值越轻视。
好了,现在开始我们的正题,下面我们讲一下MACD策略。
MAC策略是什么
MACD是从双指数移动平均线发展而来的,由快的指数移动平均数(EMA12)减去慢的指数移动平均数(EMA26)
当MACD线上穿signal线的时候看涨。(买入信号)
当MACD线下穿signal线的时候看跌。(卖出信号)
其中signal线是MACD的EMA(9)
总结公式如下:
- MACD=价格EMA(12) - 价格EMA(26).
- signal线=MACD的EMA(9)
于是,我们有了下面的策略
买入:当MACD线在前一天的值 < 信号线前一天的值,同时,当天MACD线的值 > 当天信号线的值时,说明发生了金叉,此时看涨,第二天买入。
卖出:若已盈利10%,则卖出;若已亏损10%,则卖出。
代码
数据文件603186.csv,如下
603186.csv
#-*- coding:utf-8 -*-# @Time:2021/5/19 11:12import datetimeimport backtrader as bt# dataclose[0] # 当日的收盘价# dataclose[-1] # 昨天的收盘价# dataclose[-2] # 前天的收盘价class TestStrategy(bt.Strategy):"""继承并构建自己的bt策略"""def __init__(self):# 初始化相关数据self.dataclose = self.datas[0].closeself.order = Noneself.buyprice = Noneself.buycomm = None# self.volume = self.datas[0].volumeself.me12 = bt.indicators.EMA(self.data, period=12)self.me26 = bt.indicators.EMA(self.data, period=26)self.macd = self.me12 - self.me26self.signal = bt.indicators.EMA(self.macd, period=9)# bt.indicators.MACDHisto(self.data)def notify_order(self, order):"""订单状态处理:param order: 订单状态"""if order.status in [order.Submitted, order.Accepted]:# 如订单已被处理,则不用做任何事情return# 检查订单是否完成if order.status in [order.Completed]:if order.isbuy():self.buyprice = order.executed.priceself.buycomm = order.executed.commself.bar_executed_close = self.dataclose[0]self.bar_exected = len(self)# 订单因为缺少资金之类的原因被拒绝执行elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Caceled/Margin/Rejected')# 订单状态处理完成,设为空self.order = Nonedef notify_trade(self, trade):"""交易成果:param trade: 交易状态:return:"""if not trade.isclosed:return# 显示交易的毛利率和净利润self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm), doprint=True)def log(self, txt, dt=None, doprint=False):'''日志函数, 用于统一输出日志格式'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))returndef next(self):# 记录收盘价self.log('Close,%.2f' % self.dataclose[0])# 是否正在下单,如果是的话不能提交第二次订单if self.order:return# 是否已经买入if not self.position:# 如果没有持仓,若前一天MACD < Signal, 当天 Signal < MACD,则第二天买入if self.macd[-1] < self.signal[-1] and self.macd[0] > self.signal[0]:self.log('BUY CREATE, %.2f' % self.dataclose[0])self.order = self.buy()else:# 若已盈利10%,则卖出;若已亏损10%,则卖出。condition = (self.dataclose[0] - self.bar_executed_close) / self.dataclose[0]if condition > 0.1 or condition < -0.1:self.log('SELL CREATE, %.2f' % self.dataclose[0])self.order = self.sell()def stop(self):self.log(u'(金叉死叉有用吗) Ending Value %.2f' %(self.broker.getvalue()), doprint=True)def load_data():data = bt.feeds.GenericCSVData(dataname='603186.csv',fromdate=datetime.datetime(2010, 1, 1),todate=datetime.datetime(2020, 4, 12),dtformat='%Y%m%d',datetime=2,open=3,high=4,low=5,close=6,volume=10,reverse=True)return datadef main():# 初始化模型cerebro = bt.Cerebro()# 构建策略strats = cerebro.addstrategy(TestStrategy)# 设定买入的股数cerebro.addsizer(bt.sizers.FixedSize, stake=100)data = load_data()#加载数据到模型cerebro.adddata(data)# 设定初始资金cerebro.broker.set_cash(10000)# 设定交易佣金(万五,交易额每满一万元收取5元佣金)cerebro.broker.setcommission(0.005)# 策略执行前的资金print('Starting Portfolio Value:%.2f' % cerebro.broker.get_value())# 策略执行cerebro.run()# 策略执行后的资金print('Final Portfolio Value:%.2f' % cerebro.broker.get_value())cerebro.plot()if __name__ == '__main__':main()
结果预览

由上图可以看到,8次操作中盈利了7次,总盈利2600。
虽然量化策略是有效果的,但是最重要的还是选股,如何选到最佳的股票,就需要多看财报、多动脑了,世界上没有不劳而获的财富!
