MACD择时策略

'''
一、MACD择时策略:
    1.买入规则:DIF上穿DEA,买入股票
    2.卖出规则:DIF下穿DEA,卖出股票
    3.止损价:max(移动止损,固定止损)
           移动止损:ma - std
           固定止损:开仓价 - 开仓的std
'''
import tushare as ts
import numpy as np
import talib as ta
import seaborn as sns
import pandas as pd
from functools import reduce
from matplotlib import pyplot as plt
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname='C:/Windows/Fonts/simhei.ttf')     # 解决中文显示问题
# 选股策略部分:
def stocks_pool_list():
    '''
    预处理原则:
    * pe>0
    :return:取PE最小的10只股票代码列表
    '''
    data = ts.get_stock_basics()
    data = data[data['pe'] > 0].sort_values('pe')
    Selected_stocks_list = list(data.index[:stock_num])  # [:stock_num]
    return Selected_stocks_list
# 择时策略部分:
def timing_based_on_MACD(stocks_list, length):
    '''
    MACD择时策略:
    * 买入规则:DIF上穿DEA,买入股票
    * 卖出规则:DIF下穿DEA,卖出股票
    * 止损条件:移动止损+固定止损
    :param stocks_list:基于选出的股票代码列表
    :param length:观察期时间长短
    :return:MACD择时买卖股票的日收益率DataFrame
    '''

    # map函数 类似于遍历每一只股票,获取每只股票的累计收益
    def data(code):
        # 获取数据及数据处理
        stock = ts.get_k_data(code, start=start, end=end).loc[:, ['date', 'open', 'close', 'low']]
        close = [float(x) for x in stock['close']]
        stock['DIF'], stock['DEA'], stock['MACD'] = ta.MACD(np.asarray(close),
                                                            fastperiod=fast_period,
                                                            slowperiod=slow_period,
                                                            signalperiod=signal_period)
        stock['ma'] = stock['close'].rolling(length).mean()
        stock['std'] = stock['close'].rolling(length).std()
        stock['yes_ma'] = stock['ma'].shift(1)
        stock['yes_std'] = stock['std'].shift(1)
        stock['yes_close'] = stock['close'].shift(1)
        stock['yes_open'] = stock['open'].shift(1)
        stock['yes_MACD'] = stock['MACD'].shift(1)
        stock['beforeyes_MACD'] = stock['yes_MACD'].shift(1)
        stock.dropna(inplace=True)
        # 若MACD由正变负,卖出
        stock['signal'] = np.where(np.logical_and(stock['beforeyes_MACD'] > 0, stock['yes_MACD'] < 0), -1, 0)
        # 若MACD由负变正,买入
        stock['signal'] = np.where(np.logical_and(stock['beforeyes_MACD'] < 0, stock['yes_MACD'] > 0), 1, stock['signal'])
        stock.reset_index(inplace=True)


        # 策略逻辑
        flag = 0  # 持仓记录,1表示有仓位,0表示空仓;
        # 遍历每一天
        for i in range(len(stock)):

            # 若持有该股票,考虑止损
            if flag == 1:
                stoplose_price = max(stock.loc[i, 'yes_ma'] - stoplose_trigger * stock.loc[i, 'yes_std'],
                                     long_open_price - long_open_delta)
                # 若DIF下穿DEA,则卖出该股票
                if (stock.loc[i, 'signal'] == -1) or (stock.loc[i, 'low'] < stoplose_price):
                    flag = 0
                    # 当日收益
                    stock.loc[i, 'return'] = stock.loc[i, 'open'] / stock.loc[i, 'yes_close'] - 1

                # 若DIF没有下穿DEA,则继续持有该股票
                else:
                    # 当日收益
                    stock.loc[i, 'return'] = stock.loc[i, 'close'] / stock.loc[i, 'yes_close'] - 1

            # 2. 若不持有该股票,考虑开仓触发条件
            else:
                # 若DIF上穿DEA,则买入该股票
                if stock.loc[i, 'signal'] == 1:
                    flag = 1
                    # 开仓价格&标准差
                    long_open_price = stock.loc[i, 'open']
                    long_open_delta = stock.loc[i, 'yes_std']
                    # 当日收益
                    stock.loc[i, 'return'] = stock.loc[i, 'close'] / stock.loc[i, 'open'] - 1

                # 若DIF没有上穿DEA,则不买入
                else:
                    stock.loc[i, 'return'] = 0

        # 计算累计收益
        stock.loc[:, 'cum_return_%s' % code] = (1 + stock.loc[:, 'return']).cumprod()

        return stock.loc[:, ['date', 'cum_return_%s' % code]]

    datas = map(data, stocks_list)

    return_data = reduce(lambda x, y: pd.merge(x, y, on='date'), datas)

    return return_data
# 基准累计收益
def benchmark_return(benchmark):
    '''
    :param benchmark: 基准的股票代码
    :return: 基准的累计收益率DataFrame
    '''
    stock = ts.get_k_data(benchmark, start=start, end=end).loc[:, ['date', 'close']]
    stock['pct_change'] = stock['close'].pct_change()
    stock['benchmark_return'] = (1 + stock['pct_change']).cumprod()

    return stock[['date', 'benchmark_return']]
# 参数设置
benchmark = 'hs300'        # 策略的基准
start = '2016-01-01'       # 回测开始时间
end = '2020-04-24'         # 回测结束时间
fast_period = 12           # 快线周期
slow_period = 26           # 慢线周期
signal_period = 9          # Signal平滑周期
stock_num = 10             # 选择PE最小的股票的数量
length = 10                # 观察期时间长短
stoplose_trigger = 1       # 止损触发的几倍标准差
# 1. 选股策略部分:取PE最小的10只股票代码列表
stocks_list = stocks_pool_list()

# 2. 择时策略部分:基于选出的股票代码列表,进行MACD择时买卖股票
return_data = timing_based_on_MACD(stocks_list, length)
#   资金平均投资个股,得出策略累计收益
return_data['strategy_return'] = return_data.mean(axis=1)

# 3. 基准累计收益
benchmark_return = benchmark_return(benchmark)
all_return = pd.merge(benchmark_return, return_data[['date', 'strategy_return']], on='date')

# 4. 画图
sns.set()
all_return.plot(figsize=(12, 8))
_x = range(len(all_return.index))
_x_ticks = list(all_return['date'])
plt.xticks(_x[::30], _x_ticks[::30], rotation=45)
plt.title('MACD择时策略', fontsize=20, fontproperties=my_font)
plt.show()

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值