Skip to content

MACD 设置

原文: https://www.backtrader.com/blog/posts/2016-07-30-macd-settings/macd-settings/

RedditAlgotrading站点中发现了一条关于优化 MACD 设置的线索。

因为交易你的金融自由之路——亚马逊链接而开始了反向交易者任务,我别无选择,只能发布一个答案并制作一个样本。

战略方法大致基于书中提出的一些想法。太阳底下没有什么新鲜事。并且参数已快速设置。没有过度装配,没有优化,什么都没有。大致:

  • 如果macd线穿过signal线向上,且控制Simple Moving Average在过去 x 个周期内有净负方向(当前SMA值低于x周期前的值),则输入

  • stop价格设置为close价格的N x ATR

  • 如果close价格低于stop价格,则退出市场

  • 如果仍在市场中,则仅当stop价格高于实际价格时,才更新stop价格

立桩通过以下方式完成:

  • 拥有Sizer分配百分比的可用现金用于运营。战略赢得越多,风险就越大……损失越多,风险就越小。

包括一个委员会。由于测试将使用股票进行,因此选择了一个百分比佣金,每次往返的佣金值为0.0033(又名0.33%

为了发挥这一作用,将使用 3 个数据进行 3 次运行(总共 9 次运行)

  1. 手动选择的标准参数

  2. 将现金分配比例从0.20增加到0.50

  3. 将停车点的 ATR 距离从3.0增加到4.0,以避免被鞭打

为策略手动选择的参数:

params = (
    # Standard MACD Parameters
    ('macd1', 12),
    ('macd2', 26),
    ('macdsig', 9),
    ('atrperiod', 14),  # ATR Period (standard)
    ('atrdist', 3.0),   # ATR distance for stop price
    ('smaperiod', 30),  # SMA Period (pretty standard)
    ('dirperiod', 10),  # Lookback period to consider SMA trend direction
) 

和全系统:

parser.add_argument('--cash', required=False, action='store',
                    type=float, default=50000,
                    help=('Cash to start with'))

parser.add_argument('--cashalloc', required=False, action='store',
                    type=float, default=0.20,
                    help=('Perc (abs) of cash to allocate for ops'))

parser.add_argument('--commperc', required=False, action='store',
                    type=float, default=0.0033,
                    help=('Perc (abs) commision in each operation. '
                          '0.001 -> 0.1%%, 0.01 -> 1%%')) 

日期范围为2005-01-012014-12-31,共 10 年。

分析者

为了获得一些目标数据,系统将添加 3 个分析仪:

  • 整个期间有两个TimeReturn

    1. 对于战略本身

    2. 作为基准操作的数据

    根据资产对战略进行有效基准测试

  • ATimeReturn衡量年回报

  • ASharpeRatio查看针对无风险资产的策略执行情况

    该值设置为1%,可通过样本选项进行更改

  • ASQN系统质量编号),用于使用 Van K.Tharp 定义的绩效指标分析交易质量

此外,将向混合物中添加一个DrawDown观察者。

运行 1:标准参数

YHOO

$ ./macdsystem.py --plot --dataset yhoo
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.07118518868
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.316736183525
===============================================================================
TimeReturn:
  - 2005-12-31: 0.02323119024
  - 2006-12-31: -0.0813678018166
  - 2007-12-31: -0.0144802141955
  - 2008-12-31: -0.142301023804
  - 2009-12-31: 0.0612152927491
  - 2010-12-31: 0.00898269987778
  - 2011-12-31: -0.00845048588578
  - 2012-12-31: 0.0541362123146
  - 2013-12-31: 0.0158705967774
  - 2014-12-31: 0.0281978956007
===============================================================================
SharpeRatio:
  - sharperatio: -0.261214264357
===============================================================================
SQN:
  - sqn: -0.784558216044
  - trades: 45 

!image

奥克尔

$ ./macdsystem.py --plot --dataset orcl
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.24890384718
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 2.23991354467
===============================================================================
TimeReturn:
  - 2005-12-31: -0.02372911952
  - 2006-12-31: 0.0692563226579
  - 2007-12-31: 0.0551086853554
  - 2008-12-31: -0.026707886256
  - 2009-12-31: 0.0786118091383
  - 2010-12-31: 0.037571919146
  - 2011-12-31: 0.00846519206845
  - 2012-12-31: 0.0402937469005
  - 2013-12-31: -0.0147124502187
  - 2014-12-31: 0.00710131291379
===============================================================================
SharpeRatio:
  - sharperatio: 0.359712552054
===============================================================================
SQN:
  - sqn: 1.76240859868
  - trades: 37 

!image

NVDA

$ ./macdsystem.py --plot --dataset nvda
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.0178507058999
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.177604931253
===============================================================================
TimeReturn:
  - 2005-12-31: 0.0773031957141
  - 2006-12-31: 0.105007457325
  - 2007-12-31: 0.015286423657
  - 2008-12-31: -0.109130552525
  - 2009-12-31: 0.14716076542
  - 2010-12-31: -0.0891638005423
  - 2011-12-31: -0.0788216550171
  - 2012-12-31: -0.0498231953066
  - 2013-12-31: -0.0119166712361
  - 2014-12-31: 0.00940493597076
===============================================================================
SharpeRatio:
  - sharperatio: -0.102967601564
===============================================================================
SQN:
  - sqn: -0.0700412395071
  - trades: 38 

!image

运行 1 的分析

  • YHOO

    1st和 2ndTimeReturn分析工具(策略和资产本身)表明,策略已失去7.11%,而相关资产已升值31.67%

    甚至不值得看一看其他分析仪

  • ORCL

    A24.89%用于战略,但资产本身的223.99%回报使其黯然失色。

    位于0.35夏普拉蒂奥距离通常的最低目标1仍然很远。

    SQN返回一个1.76,该1.76至少在Van K.Tharp量表1.6 - 1.9 Below Average中获得一个等级。

  • NVDA

    在这种情况下,a-1.78%表示策略,a-17.76%表示资产。带有-0.10的 SharpeRatio 表明,即使该策略的表现优于该资产,也最好使用1%银行账户。

    SQN显然不在量表的底部。

运行 1 的结论

  • 1 重大损失,一场平局,一场胜利,表现逊于资产。没有那么成功。

运行 2:cashaloc 到 0.50

YHOO

$ ./macdsystem.py --plot --dataset yhoo --cashalloc 0.50
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.20560369198
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.316736183525
===============================================================================
TimeReturn:
  - 2005-12-31: 0.05517338686
  - 2006-12-31: -0.195123836162
  - 2007-12-31: -0.0441556438731
  - 2008-12-31: -0.32426212721
  - 2009-12-31: 0.153876836394
  - 2010-12-31: 0.0167157437151
  - 2011-12-31: -0.0202891373759
  - 2012-12-31: 0.13289763017
  - 2013-12-31: 0.0408192946307
  - 2014-12-31: 0.0685527133815
===============================================================================
SharpeRatio:
  - sharperatio: -0.154427699146
===============================================================================
SQN:
  - sqn: -0.97846453428
  - trades: 45 

!image

奥克尔

$ ./macdsystem.py --plot --dataset orcl --cashalloc 0.50
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.69016747856
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 2.23991354467
===============================================================================
TimeReturn:
  - 2005-12-31: -0.0597533502
  - 2006-12-31: 0.176988400688
  - 2007-12-31: 0.140268851352
  - 2008-12-31: -0.0685193675128
  - 2009-12-31: 0.195760054561
  - 2010-12-31: 0.0956386594392
  - 2011-12-31: 0.018709882089
  - 2012-12-31: 0.100122407053
  - 2013-12-31: -0.0375741196261
  - 2014-12-31: 0.017570390931
===============================================================================
SharpeRatio:
  - sharperatio: 0.518921692742
===============================================================================
SQN:
  - sqn: 1.68844251174
  - trades: 37 

!image

NVDA

$ ./macdsystem.py --plot --dataset nvda --cashalloc 0.50
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.128845648113
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.177604931253
===============================================================================
TimeReturn:
  - 2005-12-31: 0.200593209479
  - 2006-12-31: 0.219254906522
  - 2007-12-31: 0.0407793562989
  - 2008-12-31: -0.259567975403
  - 2009-12-31: 0.380971100974
  - 2010-12-31: -0.208860409742
  - 2011-12-31: -0.189068154062
  - 2012-12-31: -0.122095056225
  - 2013-12-31: -0.0296495770432
  - 2014-12-31: 0.0232050942344
===============================================================================
SharpeRatio:
  - sharperatio: -0.0222780544339
===============================================================================
SQN:
  - sqn: -0.190661428812
  - trades: 38 

!image

运行 2 的结论

  • 将每次操作中的现金分配百分比从20%增加到50%增加了先前结果的影响

    • YHOONVDA上的策略比以前损失更多

    • ORCL上的策略比以前赢了更多,仍然没有接近资产的220%以上

运行 3:ATR 距离到 4.0

仍将之前增加的现金分配保持在50%。这样做是为了避免过早退出市场。

YHOO

$ ./macdsystem.py --plot --dataset yhoo --cashalloc 0.50 --atrdist 4.0
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.01196310622
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.316736183525
===============================================================================
TimeReturn:
  - 2005-12-31: 0.06476232676
  - 2006-12-31: -0.220219327475
  - 2007-12-31: -0.0525484648039
  - 2008-12-31: -0.314772526784
  - 2009-12-31: 0.179631995594
  - 2010-12-31: 0.0579495723922
  - 2011-12-31: -0.0248948026947
  - 2012-12-31: 0.10922621981
  - 2013-12-31: 0.406711050602
  - 2014-12-31: -0.0113108751022
===============================================================================
SharpeRatio:
  - sharperatio: 0.0495181271704
===============================================================================
SQN:
  - sqn: -0.211652416441
  - trades: 33 

!image

奥克尔

$ ./macdsystem.py --plot --dataset orcl --cashalloc 0.50 --atrdist 4.0
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.21907748452
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 2.23991354467
===============================================================================
TimeReturn:
  - 2005-12-31: -0.06660102614
  - 2006-12-31: 0.169334910265
  - 2007-12-31: 0.10620478758
  - 2008-12-31: -0.167615289704
  - 2009-12-31: 0.17616784045
  - 2010-12-31: 0.0591200431984
  - 2011-12-31: -0.100238247103
  - 2012-12-31: 0.135096589522
  - 2013-12-31: -0.0630483842399
  - 2014-12-31: 0.0175914485158
===============================================================================
SharpeRatio:
  - sharperatio: 0.144210776122
===============================================================================
SQN:
  - sqn: 0.646519270815
  - trades: 30 

!image

NVDA

$ ./macdsystem.py --plot --dataset nvda --cashalloc 0.50 --atrdist 4.0
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: 0.48840287049
===============================================================================
TimeReturn:
  - 9999-12-31 23:59:59.999999: -0.177604931253
===============================================================================
TimeReturn:
  - 2005-12-31: 0.246510998277
  - 2006-12-31: 0.194958106054
  - 2007-12-31: -0.123140650516
  - 2008-12-31: -0.246174938322
  - 2009-12-31: 0.33121185861
  - 2010-12-31: -0.0442212647256
  - 2011-12-31: 0.0368388717861
  - 2012-12-31: -0.048473112136
  - 2013-12-31: 0.10657587649
  - 2014-12-31: 0.0883112536534
===============================================================================
SharpeRatio:
  - sharperatio: 0.264551262551
===============================================================================
SQN:
  - sqn: 0.564151633588
  - trades: 29 

!image

运行 3 的结论

  • 鸡肉,鸡肉,赢家晚餐!!

    该战略通过这三项资产赚钱

    • YHOO1.19%与资产本身的31.67%收益

    • ORCL21.90%对该资产的223.99%

    在这种情况下,增加ATRDist参数会减少运行 2之前在69.01%的返回

    • NVDA:资产的48.84%-17.76%

    令人惊讶的是,SharpeRatioSQN正在告诉我们这一点

样本的使用

$ ./macdsystem.py --help
usage: macdsystem.py [-h] (--data DATA | --dataset {yhoo,orcl,nvda})
                     [--fromdate FROMDATE] [--todate TODATE] [--cash CASH]
                     [--cashalloc CASHALLOC] [--commperc COMMPERC]
                     [--macd1 MACD1] [--macd2 MACD2] [--macdsig MACDSIG]
                     [--atrperiod ATRPERIOD] [--atrdist ATRDIST]
                     [--smaperiod SMAPERIOD] [--dirperiod DIRPERIOD]
                     [--riskfreerate RISKFREERATE] [--plot [kwargs]]

Sample for Tharp example with MACD

optional arguments:
  -h, --help            show this help message and exit
  --data DATA           Specific data to be read in (default: None)
  --dataset {yhoo,orcl,nvda}
                        Choose one of the predefined data sets (default: None)
  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default:
                        2005-01-01)
  --todate TODATE       Ending date in YYYY-MM-DD format (default: None)
  --cash CASH           Cash to start with (default: 50000)
  --cashalloc CASHALLOC
                        Perc (abs) of cash to allocate for ops (default: 0.2)
  --commperc COMMPERC   Perc (abs) commision in each operation. 0.001 -> 0.1%,
                        0.01 -> 1% (default: 0.0033)
  --macd1 MACD1         MACD Period 1 value (default: 12)
  --macd2 MACD2         MACD Period 2 value (default: 26)
  --macdsig MACDSIG     MACD Signal Period value (default: 9)
  --atrperiod ATRPERIOD
                        ATR Period To Consider (default: 14)
  --atrdist ATRDIST     ATR Factor for stop price calculation (default: 3.0)
  --smaperiod SMAPERIOD
                        Period for the moving average (default: 30)
  --dirperiod DIRPERIOD
                        Period for SMA direction calculation (default: 10)
  --riskfreerate RISKFREERATE
                        Risk free rate in Perc (abs) of the asset for the
                        Sharpe Ratio (default: 0.01)
  --plot [kwargs], -p [kwargs]
                        Plot the read data applying any kwargs passed For
                        example: --plot style="candle" (to plot candles)
                        (default: None) 

还有代码本身

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse
import datetime
import random

import backtrader as bt

BTVERSION = tuple(int(x) for x in bt.__version__.split('.'))

class FixedPerc(bt.Sizer):
    '''This sizer simply returns a fixed size for any operation

    Params:
      - ``perc`` (default: ``0.20``) Perc of cash to allocate for operation
    '''

    params = (
        ('perc', 0.20),  # perc of cash to use for operation
    )

    def _getsizing(self, comminfo, cash, data, isbuy):
        cashtouse = self.p.perc * cash
        if BTVERSION > (1, 7, 1, 93):
            size = comminfo.getsize(data.close[0], cashtouse)
        else:
            size = cashtouse // data.close[0]
        return size

class TheStrategy(bt.Strategy):
    '''
    This strategy is loosely based on some of the examples from the Van
    K. Tharp book: *Trade Your Way To Financial Freedom*. The logic:

      - Enter the market if:
        - The MACD.macd line crosses the MACD.signal line to the upside
        - The Simple Moving Average has a negative direction in the last x
          periods (actual value below value x periods ago)

     - Set a stop price x times the ATR value away from the close

     - If in the market:

       - Check if the current close has gone below the stop price. If yes,
         exit.
       - If not, update the stop price if the new stop price would be higher
         than the current
    '''

    params = (
        # Standard MACD Parameters
        ('macd1', 12),
        ('macd2', 26),
        ('macdsig', 9),
        ('atrperiod', 14),  # ATR Period (standard)
        ('atrdist', 3.0),   # ATR distance for stop price
        ('smaperiod', 30),  # SMA Period (pretty standard)
        ('dirperiod', 10),  # Lookback period to consider SMA trend direction
    )

    def notify_order(self, order):
        if order.status == order.Completed:
            pass

        if not order.alive():
            self.order = None  # indicate no order is pending

    def __init__(self):
        self.macd = bt.indicators.MACD(self.data,
                                       period_me1=self.p.macd1,
                                       period_me2=self.p.macd2,
                                       period_signal=self.p.macdsig)

        # Cross of macd.macd and macd.signal
        self.mcross = bt.indicators.CrossOver(self.macd.macd, self.macd.signal)

        # To set the stop price
        self.atr = bt.indicators.ATR(self.data, period=self.p.atrperiod)

        # Control market trend
        self.sma = bt.indicators.SMA(self.data, period=self.p.smaperiod)
        self.smadir = self.sma - self.sma(-self.p.dirperiod)

    def start(self):
        self.order = None  # sentinel to avoid operrations on pending order

    def next(self):
        if self.order:
            return  # pending order execution

        if not self.position:  # not in the market
            if self.mcross[0] > 0.0 and self.smadir < 0.0:
                self.order = self.buy()
                pdist = self.atr[0] * self.p.atrdist
                self.pstop = self.data.close[0] - pdist

        else:  # in the market
            pclose = self.data.close[0]
            pstop = self.pstop

            if pclose < pstop:
                self.close()  # stop met - get out
            else:
                pdist = self.atr[0] * self.p.atrdist
                # Update only if greater than
                self.pstop = max(pstop, pclose - pdist)

DATASETS = {
    'yhoo': '../../datas/yhoo-1996-2014.txt',
    'orcl': '../../datas/orcl-1995-2014.txt',
    'nvda': '../../datas/nvda-1999-2014.txt',
}

def runstrat(args=None):
    args = parse_args(args)

    cerebro = bt.Cerebro()
    cerebro.broker.set_cash(args.cash)
    comminfo = bt.commissions.CommInfo_Stocks_Perc(commission=args.commperc,
                                                   percabs=True)

    cerebro.broker.addcommissioninfo(comminfo)

    dkwargs = dict()
    if args.fromdate is not None:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dkwargs['fromdate'] = fromdate

    if args.todate is not None:
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dkwargs['todate'] = todate

    # if dataset is None, args.data has been given
    dataname = DATASETS.get(args.dataset, args.data)
    data0 = bt.feeds.YahooFinanceCSVData(dataname=dataname, **dkwargs)
    cerebro.adddata(data0)

    cerebro.addstrategy(TheStrategy,
                        macd1=args.macd1, macd2=args.macd2,
                        macdsig=args.macdsig,
                        atrperiod=args.atrperiod,
                        atrdist=args.atrdist,
                        smaperiod=args.smaperiod,
                        dirperiod=args.dirperiod)

    cerebro.addsizer(FixedPerc, perc=args.cashalloc)

    # Add TimeReturn Analyzers for self and the benchmark data
    cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='alltime_roi',
                        timeframe=bt.TimeFrame.NoTimeFrame)

    cerebro.addanalyzer(bt.analyzers.TimeReturn, data=data0, _name='benchmark',
                        timeframe=bt.TimeFrame.NoTimeFrame)

    # Add TimeReturn Analyzers fot the annuyl returns
    cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years)
    # Add a SharpeRatio
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, timeframe=bt.TimeFrame.Years,
                        riskfreerate=args.riskfreerate)

    # Add SQN to qualify the trades
    cerebro.addanalyzer(bt.analyzers.SQN)
    cerebro.addobserver(bt.observers.DrawDown)  # visualize the drawdown evol

    results = cerebro.run()
    st0 = results[0]

    for alyzer in st0.analyzers:
        alyzer.print()

    if args.plot:
        pkwargs = dict(style='bar')
        if args.plot is not True:  # evals to True but is not True
            npkwargs = eval('dict(' + args.plot + ')')  # args were passed
            pkwargs.update(npkwargs)

        cerebro.plot(**pkwargs)

def parse_args(pargs=None):

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for Tharp example with MACD')

    group1 = parser.add_mutually_exclusive_group(required=True)
    group1.add_argument('--data', required=False, default=None,
                        help='Specific data to be read in')

    group1.add_argument('--dataset', required=False, action='store',
                        default=None, choices=DATASETS.keys(),
                        help='Choose one of the predefined data sets')

    parser.add_argument('--fromdate', required=False,
                        default='2005-01-01',
                        help='Starting date in YYYY-MM-DD format')

    parser.add_argument('--todate', required=False,
                        default=None,
                        help='Ending date in YYYY-MM-DD format')

    parser.add_argument('--cash', required=False, action='store',
                        type=float, default=50000,
                        help=('Cash to start with'))

    parser.add_argument('--cashalloc', required=False, action='store',
                        type=float, default=0.20,
                        help=('Perc (abs) of cash to allocate for ops'))

    parser.add_argument('--commperc', required=False, action='store',
                        type=float, default=0.0033,
                        help=('Perc (abs) commision in each operation. '
                              '0.001 -> 0.1%%, 0.01 -> 1%%'))

    parser.add_argument('--macd1', required=False, action='store',
                        type=int, default=12,
                        help=('MACD Period 1 value'))

    parser.add_argument('--macd2', required=False, action='store',
                        type=int, default=26,
                        help=('MACD Period 2 value'))

    parser.add_argument('--macdsig', required=False, action='store',
                        type=int, default=9,
                        help=('MACD Signal Period value'))

    parser.add_argument('--atrperiod', required=False, action='store',
                        type=int, default=14,
                        help=('ATR Period To Consider'))

    parser.add_argument('--atrdist', required=False, action='store',
                        type=float, default=3.0,
                        help=('ATR Factor for stop price calculation'))

    parser.add_argument('--smaperiod', required=False, action='store',
                        type=int, default=30,
                        help=('Period for the moving average'))

    parser.add_argument('--dirperiod', required=False, action='store',
                        type=int, default=10,
                        help=('Period for SMA direction calculation'))

    parser.add_argument('--riskfreerate', required=False, action='store',
                        type=float, default=0.01,
                        help=('Risk free rate in Perc (abs) of the asset for '
                              'the Sharpe Ratio'))
    # Plot options
    parser.add_argument('--plot', '-p', nargs='?', required=False,
                        metavar='kwargs', const=True,
                        help=('Plot the read data applying any kwargs passed\n'
                              '\n'
                              'For example:\n'
                              '\n'
                              '  --plot style="candle" (to plot candles)\n'))

    if pargs is not None:
        return parser.parse_args(pargs)

    return parser.parse_args()

if __name__ == '__main__':
    runstrat() 

我们一直在努力

apachecn/AiLearning

【布客】中文翻译组