MACD 设置
原文: https://www.backtrader.com/blog/posts/2016-07-30-macd-settings/macd-settings/
在Reddit的Algotrading站点中发现了一条关于优化 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 次运行)
- 
手动选择的标准参数 
- 
将现金分配比例从 0.20增加到0.50
- 
将停车点的 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-01至2014-12-31,共 10 年。
分析者
为了获得一些目标数据,系统将添加 3 个分析仪:
- 
整个期间有两个 TimeReturn- 
对于战略本身 
- 
作为基准操作的数据 
 根据资产对战略进行有效基准测试 
- 
- 
A TimeReturn衡量年回报
- 
A SharpeRatio查看针对无风险资产的策略执行情况该值设置为 1%,可通过样本选项进行更改
- 
A SQN(系统质量编号),用于使用 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 
奥克尔
$ ./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 
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 
运行 1 的分析
- 
YHOO 1st和 2nd TimeReturn分析工具(策略和资产本身)表明,策略已失去7.11%,而相关资产已升值31.67%。甚至不值得看一看其他分析仪 
- 
ORCL A 24.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 
奥克尔
$ ./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 
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 
运行 2 的结论
- 
将每次操作中的现金分配百分比从 20%增加到50%增加了先前结果的影响- 
YHOO和NVDA上的策略比以前损失更多 
- 
而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 
奥克尔
$ ./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 
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 
运行 3 的结论
- 
鸡肉,鸡肉,赢家晚餐!! 该战略通过这三项资产赚钱 - 
YHOO: 1.19%与资产本身的31.67%收益
- 
ORCL: 21.90%对该资产的223.99%
 在这种情况下,增加 ATRDist参数会减少运行 2之前在69.01%的返回- NVDA:资产的48.84%对-17.76%。
 令人惊讶的是,SharpeRatio和SQN正在告诉我们这一点 
- 
样本的使用
$ ./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() 










