zoukankan      html  css  js  c++  java
  • PyalgoTrade 优化(六)

    满足优化器组件。这个想法很简单:

    有一个服务器负责:

    • 提供数据来运行策略。

    • 提供运行策略的参数。

    • 记录每个工作线程的策略结果。

    有多名工作人员负责:

    • 使用服务器提供的数据和参数运行策略。

    为了说明这一点,我们将使用一种称为相对强弱指标RSI2的策略,
    它需要以下参数:

    • SMA期间用于趋势识别。我们称这个entrySMA为150到250。
    • 退出点的SMA周期较小。我们称这个exitSMA为5到15之间。
    • 进入短期/长仓的RSI期间。我们称之为rsiPeriod,范围介于2到10之间。
    • 长期进仓的RSI超卖阈值。我们称此overSoldThreshold为5到25之间。
    • RSI超买买入门槛。我们称之为OverBoughtThreshold,范围为75到95。

    如果我的数学是好的,那些是4409559不同的组合。

    测试这个策略为一组参数花了大约0.16秒。如果我连续执行所有组合,我需要大约8.5天的时间来评估所有组合,并找到最佳参数。那是很长一段时间,但是如果我能够拿到10台8核电脑来完成这项工作,总时间将会下降到大约2.5个小时。
    长话短说,我们需要平行
    我们先从“道琼斯工业平均水平”下载3年的每日k线数据:

    python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('dia', 2009, 'dia-2009.csv')"
    python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('dia', 2010, 'dia-2010.csv')"
    python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('dia', 2011, 'dia-2011.csv')"
    from pyalgotrade import strategy
    from pyalgotrade.technical import ma
    from pyalgotrade.technical import rsi
    from pyalgotrade.technical import cross
    
    
    class RSI2(strategy.BacktestingStrategy):
        def __init__(self, feed, instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold):
            super(RSI2, self).__init__(feed)
            self.__instrument = instrument
            # We'll use adjusted close values, if available, instead of regular close values.
            if feed.barsHaveAdjClose():
                self.setUseAdjustedValues(True)
            self.__priceDS = feed[instrument].getPriceDataSeries()
            self.__entrySMA = ma.SMA(self.__priceDS, entrySMA)
            self.__exitSMA = ma.SMA(self.__priceDS, exitSMA)
            self.__rsi = rsi.RSI(self.__priceDS, rsiPeriod)
            self.__overBoughtThreshold = overBoughtThreshold
            self.__overSoldThreshold = overSoldThreshold
            self.__longPos = None
            self.__shortPos = None
    
        def getEntrySMA(self):
            return self.__entrySMA
    
        def getExitSMA(self):
            return self.__exitSMA
    
        def getRSI(self):
            return self.__rsi
    
        def onEnterCanceled(self, position):
            if self.__longPos == position:
                self.__longPos = None
            elif self.__shortPos == position:
                self.__shortPos = None
            else:
                assert(False)
    
        def onExitOk(self, position):
            if self.__longPos == position:
                self.__longPos = None
            elif self.__shortPos == position:
                self.__shortPos = None
            else:
                assert(False)
    
        def onExitCanceled(self, position):
            # If the exit was canceled, re-submit it.
            position.exitMarket()
    
        def onBars(self, bars):
            # Wait for enough bars to be available to calculate SMA and RSI.
            if self.__exitSMA[-1] is None or self.__entrySMA[-1] is None or self.__rsi[-1] is None:
                return
    
            bar = bars[self.__instrument]
            if self.__longPos is not None:
                if self.exitLongSignal():
                    self.__longPos.exitMarket()
            elif self.__shortPos is not None:
                if self.exitShortSignal():
                    self.__shortPos.exitMarket()
            else:
                if self.enterLongSignal(bar):
                    shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
                    self.__longPos = self.enterLong(self.__instrument, shares, True)
                elif self.enterShortSignal(bar):
                    shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
                    self.__shortPos = self.enterShort(self.__instrument, shares, True)
    
        def enterLongSignal(self, bar):
            return bar.getPrice() > self.__entrySMA[-1] and self.__rsi[-1] <= self.__overSoldThreshold
    
        def exitLongSignal(self):
            return cross.cross_above(self.__priceDS, self.__exitSMA) and not self.__longPos.exitActive()
    
        def enterShortSignal(self, bar):
            return bar.getPrice() < self.__entrySMA[-1] and self.__rsi[-1] >= self.__overBoughtThreshold
    
        def exitShortSignal(self):
            return cross.cross_below(self.__priceDS, self.__exitSMA) and not self.__shortPos.exitActive()

    服务器脚本

    import itertools
    from pyalgotrade.barfeed import yahoofeed
    from pyalgotrade.optimizer import server
    
    
    def parameters_generator():
        instrument = ["dia"]
        entrySMA = range(150, 251)
        exitSMA = range(5, 16)
        rsiPeriod = range(2, 11)
        overBoughtThreshold = range(75, 96)
        overSoldThreshold = range(5, 26)
        return itertools.product(instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold)
    
    # The if __name__ == '__main__' part is necessary if running on Windows.
    if __name__ == '__main__':
        # Load the feed from the CSV files.
        feed = yahoofeed.Feed()
        feed.addBarsFromCSV("dia", "dia-2009.csv")
        feed.addBarsFromCSV("dia", "dia-2010.csv")
        feed.addBarsFromCSV("dia", "dia-2011.csv")
    
        # Run the server.
        server.serve(feed, parameters_generator(), "localhost", 5000)

    服务器代码正在做3件事情:

    • 声明生成函数,为该策略产生不同的参数组合。
    • 使用我们下载的CSV文件加载Feed。
    • 运行端口5000上等待传入连接的服务器。
      这是使用pyalgotrade.optimizer.worker模块与服务器提供的数据并行运行策略的工作脚本:
    from pyalgotrade.optimizer import worker
    import rsi2
    
    # The if __name__ == '__main__' part is necessary if running on Windows.
    if __name__ == '__main__':
        worker.run(rsi2.RSI2, "localhost", 5000, workerName="localworker")

    当您运行服务器和客户端时,您将在服务器控制台上看到类似的内容:

    2014-05-03 15:04:01,083 server [INFO] Loading bars
    2014-05-03 15:04:01,348 server [INFO] Waiting for workers
    2014-05-03 15:04:58,277 server [INFO] Partial result 1242173.28754 with parameters: ('dia', 150, 5, 2, 91, 19) from localworker
    2014-05-03 15:04:58,566 server [INFO] Partial result 1203266.33502 with parameters: ('dia', 150, 5, 2, 81, 19) from localworker
    2014-05-03 15:05:50,965 server [INFO] Partial result 1220763.1579 with parameters: ('dia', 150, 5, 3, 83, 24) from localworker
    2014-05-03 15:05:51,325 server [INFO] Partial result 1221627.50793 with parameters: ('dia', 150, 5, 3, 80, 24) from localworker
    .
    .

    在工作台的控制台上有这样的东西:

    2014-05-03 15:02:25,360 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 84, 15)
    2014-05-03 15:02:25,377 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 94, 5)
    2014-05-03 15:02:25,661 localworker [INFO] Result 1090481.06342
    2014-05-03 15:02:25,661 localworker [INFO] Result 1031470.23717
    2014-05-03 15:02:25,662 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 93, 25)
    2014-05-03 15:02:25,665 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 84, 14)
    2014-05-03 15:02:25,995 localworker [INFO] Result 1135558.55667
    2014-05-03 15:02:25,996 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 93, 24)
    2014-05-03 15:02:26,006 localworker [INFO] Result 1083987.18174
    2014-05-03 15:02:26,007 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 84, 13)
    2014-05-03 15:02:26,256 localworker [INFO] Result 1093736.17175
    2014-05-03 15:02:26,257 localworker [INFO] Running strategy with parameters ('dia', 150, 5, 2, 84, 12)
    2014-05-03 15:02:26,280 localworker [INFO] Result 1135558.55667
    .
    .

    请注意,您应该只运行一个服务器和一个或多个工作。
    如果您只想在自己的桌面上并行运行策略,您可以利用pyalgotrade.optimizer.local 模块,如下所示:

    import itertools
    from pyalgotrade.optimizer import local
    from pyalgotrade.barfeed import yahoofeed
    import rsi2
    
    
    def parameters_generator():
        instrument = ["dia"]
        entrySMA = range(150, 251)
        exitSMA = range(5, 16)
        rsiPeriod = range(2, 11)
        overBoughtThreshold = range(75, 96)
        overSoldThreshold = range(5, 26)
        return itertools.product(instrument, entrySMA, exitSMA, rsiPeriod, overBoughtThreshold, overSoldThreshold)
    
    
    # The if __name__ == '__main__' part is necessary if running on Windows.
    if __name__ == '__main__':
        # Load the feed from the CSV files.
        feed = yahoofeed.Feed()
        feed.addBarsFromCSV("dia", "dia-2009.csv")
        feed.addBarsFromCSV("dia", "dia-2010.csv")
        feed.addBarsFromCSV("dia", "dia-2011.csv")
    
        local.run(rsi2.RSI2, feed, parameters_generator())

    代码正在做3件事情:
    1.声明生成不同参数组合的生成函数。
    2.使用我们下载的CSV文件加载Feed。
    3.使用pyalgotrade.optimizer.local模块并行运行策略,找到最佳结果。
    当您运行此代码时,您应该看到如下:

    2014-05-03 15:08:06,587 server [INFO] Loading bars
    2014-05-03 15:08:06,910 server [INFO] Waiting for workers
    2014-05-03 15:08:58,347 server [INFO] Partial result 1242173.28754 with parameters: ('dia', 150, 5, 2, 91, 19) from worker-95583
    2014-05-03 15:08:58,967 server [INFO] Partial result 1203266.33502 with parameters: ('dia', 150, 5, 2, 81, 19) from worker-95584
    2014-05-03 15:09:52,097 server [INFO] Partial result 1220763.1579 with parameters: ('dia', 150, 5, 3, 83, 24) from worker-95584
    2014-05-03 15:09:52,921 server [INFO] Partial result 1221627.50793 with parameters: ('dia', 150, 5, 3, 80, 24) from worker-95583
    2014-05-03 15:10:40,826 server [INFO] Partial result 1142162.23912 with parameters: ('dia', 150, 5, 4, 76, 17) from worker-95584
    2014-05-03 15:10:41,318 server [INFO] Partial result 1107487.03214 with parameters: ('dia', 150, 5, 4, 83, 17) from worker-95583
    .
    .

    为了记录,发现的最佳结果是$ 2314.40,具有以下参数:

    • entrySMA:154
    • exitSMA:5
    • rsiPeriod:2
    • overBoughtThreshold:91
    • overSoldThreshold:18



    作者:readilen
    链接:http://www.jianshu.com/p/8c43f54cf7a1
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    [置顶] Django 微信开发(一)——环境搭建
    opencv学习_5 (IplImage的结构)
    HDU 3910 (13.10.31)
    Python源码学习七 .py文件的解释
    Android高效加载大图、多图解决方案,有效避免程序内存溢出现象
    记录cocos2d-html5与cocosd-x jsb中遇到的坑
    【PAT Advanced Level】1011. World Cup Betting (20)
    Linux文件实时同步,可实现一对多
    mahout源码分析之DistributedLanczosSolver(五)Job over
    php引入lucene方法
  • 原文地址:https://www.cnblogs.com/zhanglong8681/p/7569235.html
Copyright © 2011-2022 走看看