知足優化器組件。這個想法很簡單:python
提供數據來運行策略。數組
提供運行策略的參數。服務器
記錄每一個工做線程的策略結果。函數
爲了說明這一點,咱們將使用一種稱爲相對強弱指標RSI2的策略,
它須要如下參數:測試
若是個人數學是好的,那些是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()
服務器腳本code
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件事情:server
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")
當您運行服務器和客戶端時,您將在服務器控制檯上看到相似的內容:get
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,具備如下參數:
做者:readilen連接:http://www.jianshu.com/p/8c43f54cf7a1來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。