名词解释
均线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:12
import datetime
import backtrader as bt
# dataclose[0] # 当日的收盘价
# dataclose[-1] # 昨天的收盘价
# dataclose[-2] # 前天的收盘价
class TestStrategy(bt.Strategy):
"""
继承并构建自己的bt策略
"""
def __init__(self):
# 初始化相关数据
self.dataclose = self.datas[0].close
self.order = None
self.buyprice = None
self.buycomm = None
# self.volume = self.datas[0].volume
self.me12 = bt.indicators.EMA(self.data, period=12)
self.me26 = bt.indicators.EMA(self.data, period=26)
self.macd = self.me12 - self.me26
self.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.price
self.buycomm = order.executed.comm
self.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 = None
def 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))
return
def 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 data
def 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。
虽然量化策略是有效果的,但是最重要的还是选股,如何选到最佳的股票,就需要多看财报、多动脑了,世界上没有不劳而获的财富!