小指标大用处-巧用MACD指标做ETF择时:实现年化28+\%收益

阿凡
阿凡 2025,大牛市快来了 V:flj99103681

5 人点赞了该文章 · 690 浏览

为了感谢管理员通过我的专栏申请,再分享一个实盘策略。

这次的策略,我曾经在ptrade上实盘过1年多,由于标的盘口原因,上不了规模,但确实是盈亏比非常合适的策略,在这里分享给大家。

回顾下策略核心,它是利用经典的 MACD 指标进行交易决策,选定了512670、512480、513050三个ETF作为操作标的。每天开盘前 9:00 准备就绪,记录当天日期;开盘时段按 5 分钟间隔检查股票 MACD 指标,依据 DIFF 线与 0 轴的交叉情况,结合持仓状态决定买卖操作;收盘后记录当天交易结束时间,方便复盘。

注意:这个策略在不同的标的上,表现差异较大,所以,需要挑选合适的标的。

看看回测数据呈现出的策略表现:

  • 收益对比:策略收益达到了惊人的 172.9%,而同期基准收益却是 -5.49%,这一正一负的鲜明对比,直观展现出策略在盈利能力上远超基准。

  • 年化收益率:策略年化收益率为 28.53%,意味着长期下来每年有这样可观的增值速度,反观基准年化收益仅 -1.4%,进一步凸显策略优势。

  • 风险评估指标

  • Alpha 值为 0.28,说明策略相对基准有一定的超额收益获取能力。

  • Beta 值 0.46,显示策略与市场的相关性程度,相对较低的数值表明策略受市场整体波动影响较小。

  • Sharpe 比率达到 1.56,这可是衡量风险调整后收益的关键指标,越高说明在同等风险下收益越好,咱这策略表现相当亮眼。

  • Sortino 比率 2.47,着重考量下行风险下的收益,数值越高,在面对不利行情时策略的表现越佳。

  • 其他关键指标

  • Information Ratio 为 1.42,反映策略主动管理风险获取超额收益的能力。

  • Volatility 即波动率为 0.17,体现收益的波动幅度较小,收益稳定性较好。

  • 最大回撤 10.76%,表示策略在最不利阶段的净值下跌幅度,处于相对可控范围。

  • Tracking Error 为 0.18,说明策略与基准的偏离程度,一定程度反映策略的独立性。

  • Downside Risk 为 0.11,再次强调下行风险状况。

  • 胜率 45.8%,意味着交易成功次数占比近半,而次胜率 38.55% 也为策略表现提供了更多细节支撑。


下面是回测的截图:


接下来是源代码,欢迎交流。因为ptrade账号注销,ptrade的代码没有保留。这份代码是基于其他量化平台的,修改部分函数名后,可以在ptrade平台上直接运行。如果需要交流代码,也可以私信我。

# 股票策略模版
# 引入talib库
import talib

def init(context):
    # 设置基准收益:沪深300指数
    set_benchmark('512100.SH')
    # 打印日志
    log.info('策略开始运行,初始化函数全局只运行一次')
    # 设置股票每笔交易的手续费为万分之一点五(手续费在买卖成交后扣除,不包括税费,税费在卖出成交后扣除)
    set_commission(PerShare(type='stock',cost=0.00015))
    # 设置股票交易滑点0.05%,表示买入价为实际价格乘1.0005,卖出价为实际价格乘0.9995
    set_slippage(PriceSlippage(0.000))
    # 设置日级最大成交比例25%,分钟级最大成交比例50%
    # 日频运行时,下单数量超过当天真实成交量25%,则全部不成交
    # 分钟频运行时,下单数量超过当前分钟真实成交量50%,则全部不成交
    set_volume_limit(0.25,0.5)
    # 设置要操作的股票:
    g.security = ['512670.SH','512480.SH','513050.SH'] #输入股票代码,'513050.SH'
    #设置MACD模型参数
    g.Short = 12 #短周期平滑均线参数
    g.Long = 26 #长周期平滑均线参数
    g.M = 9 #DIFF的平滑均线参数
    g.day_Short = 12 #短周期平滑均线参数
    g.day_Long = 26 #长周期平滑均线参数
    g.day_M = 9 #DIFF的平滑均线参数

#每日开盘前9:00被调用一次,用于储存自定义参数、全局变量,执行盘前选股等
def before_trading(context):

    # 获取日期
    date = get_datetime().strftime('%Y-%m-%d %H:%M:%S')

    # 打印日期
    log.info('{} 盘前运行'.format(date))

## 开盘时运行函数
def handle_bar(context, bar_dict):
    if is_multiple_of_5_minutes(get_datetime()):
        for stock_code in g.security:
            diff,dea,macd = get_macd(stock_code)
            if diff[-1]>0 and diff[-2]<0  and context.portfolio.stock_account.positions[stock_code].amount == 0:
                log.info("======================触发买入信号",stock_code)
                av_cash = context.portfolio.stock_account.available_cash
                target_postion = context.portfolio.total_value/len(g.security)
                target_val = min(av_cash,target_postion)
                order_id = order_value(stock_code,target_val)  
                try:
                    log.info(order_id)
                    avg_price =get_order(order_id).avg_price
                    log.info("买入 %s" % (stock_code),"价格 %F" % (avg_price))
                except:
                    log.info("买入 %s" % (stock_code))
            if  diff[-1]<0  and context.portfolio.stock_account.positions[stock_code].available_amount > 0:    
                log.info("======================触发卖出信号",stock_code)
                try:
                    order_id = order_target(stock_code,0)
                    log.info(order_id)
                    avg_price =get_order(order_id).avg_price
                    log.info("卖出 %s" % (stock_code),"价格 %F" % (avg_price))
                except:
                    log.info("卖出 %s" % (stock_code))
                
## 获取macd指标    
def get_macd(stock):
    price = history(stock, ['close'], 100, '5m', True, 'pre', is_panel=1)['close']
    DIFF, DEA, MACD = talib.MACD(price.values,
    fastperiod = g.Short, slowperiod = g.Long, signalperiod = g.M)
    return DIFF,DEA,MACD

## 获取macd指标    
def get_day_macd(stock):
    price = history(stock, ['close'], 500, '30m', True, 'pre', is_panel=1)['close']
    DIFF, DEA, MACD = talib.MACD(price.values,
    fastperiod = g.day_Short, slowperiod = g.day_Long, signalperiod = g.M)
    return DIFF,DEA,MACD
    
## 判断是否是5分钟
def is_multiple_of_5_minutes(dt):
    minutes = dt.minute
    return minutes % 5 == 0

## 收盘后运行函数,用于储存自定义参数、全局变量,执行盘后选股等
def after_trading(context):

    # 获取时间
    time = get_datetime().strftime('%Y-%m-%d %H:%M:%S')
    # 打印时间
    log.info('{} 盘后运行'.format(time))
    log.info('一天结束')

北京炒家的打首板模式很火,近期在研究如何通过ptrade进行自动监控首板并第一时间参与扫板。

目前已经完成了简单的交易框架代码,有兴趣的朋友也欢迎一起交流。

发布于 2025-01-02 22:43

免责声明:

本文由 阿凡 原创发布于 百果量化交流平台 ,著作权归作者所有。

登录一下,更多精彩内容等你发现,贡献精彩回答,参与评论互动

登录! 还没有账号?去注册

9988
2025-02-10 21:48
我回测了一下,收益也是0,怎么回事? 2025-02-10 21:44:50 开始运行回测, 策略名称: ETF 2025-02-07 15:30:00 - INFO - 正在进行回测统计数据汇总 2025-02-07 15:30:00 - INFO - 回测统计数据汇总完成 2025-02-10 21:44:55 策略回测结束
阿凡
2025-01-17 17:48
最近市场行情不太行, 首板模式也亏得不要不要的
阿凡
2025-01-17 17:47
@10119038DZ 需要回测一下标的的历史表现。 我选的这三个都是历史回测很好的。
10119038DZ
2025-01-16 15:59
请教老师,在这个策略中 “# 设置要操作的股票” 应选择满足哪些基本条件的股票呢?谢谢老师
阿凡
2025-01-15 18:05
你是回测收益都是0?不会啊,我有个模拟盘一直在跑。最新的情况是运行天数212天,年化收益68.72\%,最大回撤6.74\%,累计收益35.16\%。同期沪深300ETF收益是7.35\%
lzlu520
2025-01-14 21:24
试了一下。收益都是0
lzlu520
2025-01-14 21:12
最后这句话有兴趣