Optimizing Strategy with IBStore data returns pickle error



  • I'm not sure if I'm doing this correctly: Trying the Quickstart code with Optimization and using Interactive Brokers IBStore data, I get

    File "C:\Program Files\Anaconda2\lib\multiprocessing\pool.py", line 668, in next
    raise value TypeError: can't pickle thread.lock objects
    

    Full code is below. Am I doing something wrong? Maybe it's my environment (windows with Anaconda). I haven't been able to find any similar issues in the discussion threads.

    from __future__ import (absolute_import, division, print_function,
    						unicode_literals)
    						# -*- coding: utf-8 -*-
    
    import backtrader as bt
    import datetime # for datetime objects
    import os.path # to manage paths
    from backtrader.stores import ibstore
    # import sys # to detrmine the script name in argv[0]
    
    # -----  STRATEGY DEFINITION -----
    
    
    class TestStrategy(bt.Strategy):
    	def log(self,txt,dt=None):
    		''' Logging function fot this strategy'''
    		dt = dt or self.datas[0].datetime.date(0)
    		print('%s, %s' % (dt.isoformat(),txt))
    		
    	def __init__(self):
    		# Keep a reference to the "close" line in the data[0] dataseries
    		self.dataclose = self.datas[0].close
    
    		# To keep track of pending orders and buy price/commission                        
    		self.order = None
    		self.buyprice = None
    		self.buycomm = None
    		
    		
    	def notify(self, order):
    		if order.status in [order.Submitted, order.Accepted]:
    			# Buy/Sell order submitted/accepted to/by broker - Nothing to do
    			return
    
    		# Check if an order has been completed
    		# Attention: broker could reject order if not enougth cash
    		if order.status in [order.Completed, order.Canceled, order.Margin]:
    			if order.isbuy():
    				self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
    				(order.executed.price,
    				 order.executed.value,
    				 order.executed.comm))
    				self.buyprice = order.executed.price
    				self.buycomm = order.executed.comm
    			else:  #Sell
    				self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
    				(order.executed.price,
    				 order.executed.value,
    				 order.executed.comm))
    				 
    			self.bar_executed = len(self)
    		
    		# Write down: no pending order
    		self.order = None
    		
    	def notify_trade(self, trade):
    		if not trade.isclosed:
    			return
    				  
    		self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
    			(trade.pnl, trade.pnlcomm))
    		
    		
    	def next(self):
    		# Simply log the closing price of the series from the reference
    		self.log('Close, %.2f' % self.dataclose[0])
    		# Check if an order is pending ... if yes, we cannot send a 2nd one
    		if self.order:
    			return
    		# Check if we are in the market
    		if not self.position:
    			# Not yet ... we MIGHT BUY if ...
    		# -------  STRATEGY LOGIC -----
    			if self.dataclose[0] < self.dataclose[-1]:
    				#i.e. current close less than previous close
    				if self.dataclose[-1] < self.dataclose[-2]:
    					
    					# buy with default params
    					self.log('BUY CREATE, %.2f' % self.dataclose[0])                 
    					# Keep track of the created order to avoid a 2nd order
    					self.order = self.buy()
    		else:
    			# Already in the market... we might sell if holding > 5 bars
    			if len(self) > (self.bar_executed + 5):
    				# SELL, SELL, SELL!!! (with all possible default parameters)
    				self.log('SELL CREATE, %.2f' % self.dataclose[0])
    			# Keep track of the created order to avoid a 2nd order
    				self.order = self.sell()
    			
    # -----  END STRATEGY DEFINITION -----
    					
    				
    if __name__ == '__main__':
    	# create a cerebro entity
    	cerebro = bt.Cerebro()
    	
    	# Add a strategy
      
    	cerebro.optstrategy(
    		TestStrategy,
    		maperiod=range(10, 31))
      
    	
    # Create a Data Feed
    	ibstore = bt.stores.IBStore(host='127.0.0.1',port=7496,clientId=5)
    	mysymbol = 'EUR.USD-CASH-IDEALPRO'
    	fromdate = datetime.datetime(2016,3,1,00,00)
    	todate = fromdate = datetime.datetime(2017,3,30,00,00)
    
    	data = ibstore.getdata(dataname=mysymbol, timeframe=bt.TimeFrame.Days, compression=1, fromdate=fromdate, todate=todate, historical=True)
    
    #    cerebro.resampledata(data, timeframe=bt.TimeFrame.minutes, compression=60)
    	
    	# Add the Data Feed to Cerebro
    	cerebro.adddata(data)
    	
    	
    	cerebro.broker.setcash(100000)
    	cerebro.broker.setcommission(commission=0.001) # 0.1% ... divide by 100 to remove the %
    	
    	print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    	
    	cerebro.run()
    	
    	print('Final Portfolio Value:  %.2f' % cerebro.broker.getvalue())


  • Solved: adding the 'maxcpus=1' parameter to the cerebro call worked

    ie.:

    cerebro = bt.Cerebro(maxcpus=1)
    

    Not sure why this is... perhaps because of the way data requests to IB are split into tasks.


  • administrators

    Threads are part of the pack when using IbPy and they are not pickable across processes. A lot of tweaking might be needed to remove all those objects after a historical download.


Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.