利用粒子群優化演算法(PSO)來優化vnpy的量化策略引數
上一篇文章中說要用PSO演算法來做量化策略優化,模仿DEAP的示例程式碼,做了一個單執行緒的類,實現優化。裡面程式碼結構是和之前做利用遺傳演算法優化的基本一樣。
粒子全演算法可以看看我之前文章,抄的分析結果:
粒子群演算法比遺傳演算法具有更高效的資訊共享機制,更新群體極值使得資訊實現全域性範圍共享,但遺傳演算法通過交叉和變異擁有比粒子群演算法更有效的逃離區域性最優解的概率。
下面簡單說說程式碼:
1、靜態函式object_func,本函式為優化目標函式,根據隨機生成的策略引數,執行回測後自動返回1個結果指標:夏普比率 這個是直接抄GenticOptimize2V的。這個獨立出來是為了之後多執行緒實現。這裡傳入的是一個[{key1:para},{key2,para}] 這樣結構的引數佇列。
2、類PSOOptimize,放置主要函式如下:
2.1、__init__ 物件初始化,需要傳入的引數是Strategy量化策略, Symbollist回測品種, Parameterlist引數範圍。
2.2、creator.create("FitnessMax", base.Fitness, weights=(1.0,)) 定義優化方向
creator.create("Particle", list, fitness=creator.FitnessMax, speed=list, pmin = list, pmax = list,smin=list, smax=list, parameterPackage = dict, best=None)
定義粒子類,其中包括引數list,回測返回結果,速度list,所在範圍上下限佇列,和速度
上下限
佇列;還有一個打包的引數字典,主要為了之後多執行緒呼叫。和示例程式碼對比最大區別就是多了所在範圍上線,因為如果沒有,會出現負引數的情況報錯。
2.3、particle_generate, 生成粒子,包含隨機位置,和速度;這裡面只支援(start,end,pace) 這樣一種引數範圍賦值。start和end就是位置範圍上下限。步長pace就是速度上限,負pace就是速度下限。
2.4、updateParticle,更新粒子資訊,根據粒子群最佳位置best,去更新粒子part的位置和速度。如果速度或位置在上下限,就去上下限值。如果位置值是整數,比是MAwindow這樣,就會更新值也是整數。
速度公式:
v[] = v[] + c1 * rand() * (pbest[] - present[]) + c2 * rand() * (gbest[] - present[])
位置公式:
present[] = persent[] + v[]
2.5、optimize,這個沒說明好說,主要就是繫結函式到toolbox,然後定義粒子群的粒子數量,和尋覓次數。優化出最有結果。 使用pool.map實現了多執行緒
2.6、mutated, 自變異函式
示例程式碼執行結果如下,result是夏普值。
best para: [{'slMultiplier': 2.0}, {'bollDev': 2.0}, {'bollWindow': 53.0}, {'atrWindow': 37.0}, {'cciWindow': 8.0}], result:(1.194,)
------------------------------------------------------------------2019.4.15--------------------------------------------------------------------------------
增加自適應變異函式mutated,使用pool.map實現多執行緒。
可以在我的github的 PSOOptimize資料夾下載。
https://github.com/BillyZhangGuoping/MarketDataAnaylzerbyDataFrame
程式碼:
# encoding: UTF-8 """ 展示如何實現PSO粒子群優化VNPY策略引數 1、靜態函式object_func,本函式為優化目標函式,根據隨機生成的策略引數,執行回測後自動返回1個結果指標:夏普比率 這個是直接抄GenticOptimize2V的。這個獨立出來是為了之後多執行緒實現。這裡傳入的是一個[{key1:para},{key2,para}] 這樣結構的引數佇列。 2、類PSOOptimize,放置主要函式如下: 2.1、__init__ 物件初始化,需要傳入的引數是Strategy量化策略, Symbollist回測品種, Parameterlist引數範圍。 2.2、creator.create("FitnessMax", base.Fitness, weights=(1.0,)) 定義優化方向 creator.create("Particle", list, fitness=creator.FitnessMax, speed=list, pmin = list, pmax = list,smin=list, smax=list, parameterPackage = dict, best=None) 定義粒子類,其中包括引數list,回測返回結果,速度list,所在範圍上下限佇列,和速度 上下限 佇列;還有一個打包的引數字典,主要為了之後多執行緒呼叫。和示例程式碼對比最大區別就是多了所在範圍上線,因為如果沒有,會出現負引數的情況報錯。 2.3、particle_generate, 生成粒子,包含隨機位置,和速度;這裡面只支援(start,end,pace) 這樣一種引數範圍賦值。start和end就是位置範圍上下限。步長pace就是速度上限,負pace就是速度下限。 2.4、updateParticle,更新粒子資訊,根據粒子群最佳位置best,去更新粒子part的位置和速度。如果速度或位置在上下限,就去上下限值。如果位置值是整數,比是MAwindow這樣,就會更新值也是整數。 速度公式: v[] = v[] + c1 * rand() * (pbest[] - present[]) + c2 * rand() * (gbest[] - present[]) 位置公式: present[] = persent[] + v[] 2.5、optimize,這個沒說明好說,主要就是繫結函式到toolbox,然後定義粒子群的粒子數量,和尋覓次數。優化出最有結果。 使用pool.map實現了多執行緒 2.6、mutated, 自變異函式 """ from __future__ import division from __future__ import print_function import operator import random import numpy from deap import base from deap import creator from deap import tools from vnpy.trader.app.ctaStrategy.ctaBacktesting import BacktestingEngine, MINUTE_DB_NAME, OptimizationSetting from vnpy.trader.app.ctaStrategy.strategy.strategyBollChannel import BollChannelStrategy import multiprocessing import pandas as pd import datetime def object_func(strategy_avgTuple): """ 本函式為優化目標函式,根據隨機生成的策略引數,執行回測後自動返回1個結果指標:夏普比率 這個是直接賦值GenticOptimize2V的 """ strategy_avg = strategy_avgTuple paraSet = strategy_avgTuple.parameterPackage symbol = paraSet["symbol"] strategy = paraSet["strategy"] # 建立回測引擎物件 engine = BacktestingEngine() # 設定回測使用的資料 engine.setBacktestingMode(engine.BAR_MODE) # 設定引擎的回測模式為K線 engine.setDatabase("VnTrader_1Min_Db", symbol["vtSymbol"]) # 設定使用的歷史資料庫 engine.setStartDate(symbol["StartDate"]) # 設定回測用的資料起始日期 engine.setEndDate(symbol["EndDate"]) # 設定回測用的資料起始日期 # 配置回測引擎引數 engine.setSlippage(symbol["Slippage"]) # 1跳 engine.setRate(symbol["Rate"]) # 佣金大小 engine.setSize(symbol["Size"]) # 合約大小 engine.setPriceTick(symbol["Slippage"]) # 最小价格變動 engine.setCapital(symbol["Capital"]) setting = {} for item in range(len(strategy_avg)): setting.update(strategy_avg[item]) engine.clearBacktestingResult() # 載入策略 engine.initStrategy(strategy, setting) # 執行回測,返回指定的結果指標 engine.runBacktesting() # 執行回測 # 逐日回測 # engine.calculateDailyResult() backresult = engine.calculateBacktestingResult() try: sharpeRatio = round(backresult['sharpeRatio'], 3) totalResultCount = round(backresult['totalResult'],3) except Exception, e: print("Error: %s, %s" %(str(Exception),str(e))) sharpeRatio = 0 return sharpeRatio, class PSOOptimize(object): strategy = None symbol = {} parameterlist = {} parameterPackage = {} # ------------------------------------------------------------------------ def __init__(self, Strategy, Symbollist, Parameterlist): self.strategy = Strategy self.symbol = Symbollist self.parameterlist = Parameterlist self.parameterPackage = { "strategy":self.strategy, "symbol":self.symbol } creator.create("FitnessMax", base.Fitness, weights=(1.0,)) creator.create("Particle", list, fitness=creator.FitnessMax, speed=list, pmin = list, pmax = list,smin=list, smax=list, parameterPackage = dict, best=None) def particle_generate(self): """ 生產particle粒子,根據傳入設定的起始值,終止值隨機生成位置,和位置最大最小值,根據步進生成速度,和速度最大最小值 支援兩種引數設定,一個是三個元素start,end 和pace 還有一個單一不變點 """ position_list = [] speed_list = [] pmin_list = [] pmax_list = [] smin_list = [] smax_list = [] for key, value in self.parameterlist.items(): if isinstance(value, tuple): if len(value) == 3: if isinstance(value[0],int): position_list.append({key:random.randrange(value[0], value[1])}) else: position_list.append({key: random.uniform(value[0], value[1])}) pmin_list.append(value[0]) pmax_list.append(value[1]) speed_list.append(random.uniform(-value[2], value[2])) smin_list.append(-value[2]) smax_list.append(value[2]) else: print("Paramerte list incorrect") elif isinstance(value, int) or isinstance(value, float): position_list.append({key: value}) pmin_list.append(value) pmax_list.append(value) speed_list.append(0) smin_list.append(0) smax_list.append(0) else: print("Paramerte list incorrect") particle = creator.Particle(position_list) particle.speed = speed_list particle.pmin = pmin_list particle.pmax = pmax_list particle.smin = smin_list particle.smax = smax_list particle.parameterPackage = self.parameterPackage return particle def updateParticle(self,part, best, phi1, phi2): """ 根據粒子群最佳位置best,去更新粒子part的位置和速度, 速度公式: v[] = v[] + c1 * rand() * (pbest[] - present[]) + c2 * rand() * (gbest[] - present[]) 位置公式: present[] = persent[] + v[] """ u1 = (random.uniform(0, phi1) for _ in range(len(part))) u2 = (random.uniform(0, phi2) for _ in range(len(part))) v_u1 = map(operator.mul, u1, map(self.sub, part.best, part))# c1 * rand() * (pbest[] - present[]) v_u2 = map(operator.mul, u2, map(self.sub, best, part)) # c2 * rand() * (gbest[] - present[]) part.speed = list(map(operator.add, part.speed, map(operator.add, v_u1, v_u2))) for i, speed in enumerate(part.speed): if speed < part.smin: part.speed[i] = part.smin[i] elif speed > part.smax: part.speed[i] = part.smax[i] #返回現在位置,如果原來是整數,返回也是整數,否則這是浮點數; 如果超過上下限,用上下限數值 for i,item in enumerate(part): if isinstance(item.values()[0],int): positionV = round(item.values()[0] + part.speed[i]) else: positionV = item.values()[0] + part.speed[i] if positionV <= part.pmin[i] : part[i][item.keys()[0]] = part.pmin[i] elif positionV >= part.pmax[i]: part[i][item.keys()[0]] = part.pmax[i] else: part[i][item.keys()[0]] = positionV def sub(self,a,b): return a.values()[0] - b.values()[0] def mutated(self,particle,MUTPB): """ 自適應變異 :param particle: 傳入 :param MUTPB: :return: """ size = len(particle) newPart = self.particle_generate() for i in xrange(size): if random.random() < MUTPB: particle[i] = newPart[i] return particle def optimize(self): toolbox = base.Toolbox() pool = multiprocessing.Pool(processes=(multiprocessing.cpu_count())) toolbox.register("map", pool.map) toolbox.register("particle", self.particle_generate) toolbox.register("population", tools.initRepeat, list, toolbox.particle) toolbox.register("update", self.updateParticle, phi1=2.0, phi2=2.0) toolbox.register("evaluate", object_func) pop = toolbox.population(n=20) #粒子群有5個粒子 GEN = 20 #更新一千次 MUTPB = 0.1 #自適應變異概率 best = None for g in range(GEN): # for part in pop: #每次更新,計算粒子群中最優引數,並把最優值寫入best # part.fitness.values = toolbox.evaluate(part) # if not part.best or part.best.fitness < part.fitness: # part.best = creator.Particle(part) # part.best.fitness.values = part.fitness.values # if not best or best.fitness < part.fitness: # best = creator.Particle(part) # best.fitness.values = part.fitness.values fitnesses = toolbox.map(toolbox.evaluate, pop) #利用pool.map,實現多執行緒 for part, fit in zip(pop, fitnesses): part.fitness.values = fit if not part.best or part.best.fitness < part.fitness: part.best = creator.Particle(part) part.best.fitness.values = part.fitness.values if not best or best.fitness < part.fitness: best = creator.Particle(part) best.fitness.values = part.fitness.values if g < GEN - 1: #在最後一輪之前,每輪進行位置更新和變異 for i,part in enumerate(pop): toolbox.update(part, best)#更新粒子位置 if random.random() < MUTPB: #自適應變異 self.mutated(part,MUTPB) # Gather all the fitnesses in one list and print the stats return pop, best if __name__ == "__main__": Strategy = BollChannelStrategy Symbol = { "vtSymbol": 'rb1905', "StartDate": "20181001", "EndDate": "20190301", "Slippage": 1, "Size": 10, "Rate": 2 / 10000, "Capital": 10000 } Parameterlist = { 'bollWindow':(10,50,5), 'bollDev':(3.0,6.0,0.6), 'cciWindow':(10,50,5), 'atrWindow':(10,50,5), 'slMultiplier':(3.5,5.5,0.5), 'fixedSize':1 } parameterPackage = { "symbol": Symbol, "parameterlist": Parameterlist, "strategy": Strategy } PSO = PSOOptimize(Strategy, Symbol, Parameterlist) pop,best = PSO.optimize() print ("best para: %s, result:%s" %(best,best.fitness.values)) print(pop[:20]) print("-- End of (successful) %s evolution --", Symbol["vtSymbol"])
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22259926/viewspace-2644377/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 優化演算法庫DEAP的粒子群優化演算法(PSO)示例程式碼分析優化演算法
- 計算智慧(CI)之粒子群優化演算法(PSO)(一)優化演算法
- VNPY 批量優化引數,並輸出到excel優化Excel
- 群體智慧優化演算法之粒子群優化演算法優化演算法
- 一個小技巧,VNPY策略引數優化時候顯示完成數量和總數量優化
- 小科普:機器學習中的粒子群優化演算法!機器學習優化演算法
- m基於PSO粒子群最佳化的LDPC碼NMS譯碼演算法最優歸一化引數計算和誤位元速率matlab模擬演算法Matlab
- 利用遺傳演算法庫DEAP優化交易策略演算法優化
- ActiveMQ 引數優化MQ優化
- 粒子群優化演算法對BP神經網路優化 Matlab實現優化演算法神經網路Matlab
- Mysql優化系列(1)--Innodb重要引數優化MySql優化
- MySQL 效能優化之快取引數優化MySql優化快取
- m基於PSO粒子群最佳化的LDPC碼OMS譯碼演算法最優偏移引數計算和誤位元速率matlab模擬演算法Matlab
- 寫了一個類GeneticOptimizeStrategy,針對VNPY策略遺傳演算法優化演算法優化
- Myisam & InnoDB 優化引數優化
- MySQL引數配置優化MySql優化
- python多程式簡介,和VNPY多程式引數優化程式碼分析Python優化
- VNPY引數優化功能v1版本中的一個更新引數批量生成方法優化
- 併發優化 – 降低鎖顆粒優化
- 併發優化 - 降低鎖顆粒優化
- OpenCV中的SVM引數優化OpenCV優化
- Oracle可變引數的優化Oracle優化
- 【SQL優化器】初始化引數SQL優化
- Sklearn GridSearchCV 引數優化優化
- 介面優化策略優化
- 如何利用策略模式優化表單驗證模式優化
- 利用策略模式優化過多 if else 程式碼模式優化
- MySQL 資料庫效能優化之快取引數優化MySql資料庫優化快取
- SQL Server SQL效能優化之引數化SQLServer優化
- 利用 Laravel Macroable 特性優化多型引數傳遞的技巧分享LaravelMac優化多型
- swoole優化核心引數調整優化
- Nginx實戰(六) 引數優化Nginx優化
- Linux 核心引數優化(for oracle)Linux優化Oracle
- Elasticsearch效能優化引數註解Elasticsearch優化
- spark job執行引數優化Spark優化
- Mysql 效能優化--基礎引數MySql優化
- 【SQL 效能優化】引數設定SQL優化
- weblogic幾個優化引數Web優化