Live Trading / Ibbroker / Load Trades at start
-
Hi,
I use Backtrader in live mode with IB.
Each time cerebro start, the trades are not initialized. So when the strategy place an order a new trade will be open.
Is there a way to initialized the trades with the position already open ?
Thanks for the help.
Alexandre
-
By default
bt
works only with positions open by itself. You can search for discussions on this topic on the forum, maybe somebody already implemented this. -
My goal is to load the positions open by backtrader in a previous run/session.
The previous positions are also opened by bt.
But the previous trades are not recognized by bt as "bt position".Thanks for the help,
-
I have a system that provides some functionality that you are after by storing all critical variables, trade data, account data in an *.ini file which is updated on each loop of next(). While this is not exactly what you might be after, it may overcome your problem until a better solution can be found.
How my system works on initial start:
- Parent program
- Creates *.ini file
- Runs BT as subprocess
- BT starts normally
When connection fails
- notify_store receives error
- wait for connection to be restored (but BT does not resume)
- send sms alerting me of restart
- try send close position and try cancel stop loss (if any are open). API still receives these commands even when BT cannot resume.
- runstop BT
- write variable to ini file signalling shutdown (this is for the parent program to read and action)
When shutdown recognised by parent program
- kill BT
-reload BT
When BT reloads
- check if fresh start or reload.
- If reload, then init with variables from last loop of next() prior to shutdown
- If fresh start, init with normal defaults
- [Option here to recreate the positions that had to been closed when BT failed so that the strategy can continue depending on how much time and price has moved]
Here is some sample code:
NOTIFY_STORE
def notify_store(self, msg, *args, **kwargs): print('*' * 5, 'STORE NOTIF:', msg) try: if 'external transaction MARKET_ORDER' in msg: print('msg = external transaction') self.hitstoploss = 0 try: cancel = self.cancel(self.stop_ord) #CANCEL STOP LOSS print('CANCEL STOP LOSS') return except AttributeError: print('NO STOP LOSS TO CANCEL') return else: print('NOT SURE IF STOP LOSS CURRENTLY OPEN') try: message = SendSMS.client.messages.create( from_='+xxxxxxxxxx', to='+xxxxxxxxxx', body=(self.productcode + ' FAILED TO CANCEL STOP LOSS: CHECK ON PLATFORM')) except: pass return except: print('CONNECTION FAILED') print('SEND SMS') x = 1 while True: #IF INTERNET CONNECTION DOWN. WAIT UNTIL ABLE TO SEND SMS BEFORE COMMENCING RELOAD try: message = SendSMS.client.messages.create( from_='+xxxxxxxxxx', to='+xxxxxxxxxx', body=('SHUT DOWN: CLOSING POSITIONS & RELOADING')) # body=(self.productcode + ' SHUT DOWN: CLOSING POSITIONS & RELOADING: {}'.format(msg))) print('SMS SENT') break except: print('!!! CONNECTION BROKEN !!! - FAILED TO SEND SMS. RETRYING #' + str(x)) time.sleep(2) x = x + 1 pass print('GET POSITION SIZE FROM INI FILE') #READ INI TO GET POSTION SIZE. CANNOT GET POSITION SIZE FROM BROKER IF CONNECTION INTERUPTED bt_file.read_trade_ini(self) time.sleep(2) print('INI FILE READ') print('POSITION SIZE: ' + str(self.position_size)) #self.position_size IS READ FROM THE INI FILE AND GETS UPDATED ON EACH next() print('TRY TO CLOSE POSITION') time.sleep(10) try: self.close(size=self.position_size) #SEND A CLOSE ORDER. THIS WILL WORK IF API CONNECTION RE-ESTABLISHED, EVEN IF BT HAS STALLED except: pass # time.sleep(2) print('POSITION CLOSED. TRY TO CANCEL STOP LOSS') try: self.cancel(self.stop_ord) #SEND A CANCEL STOP LOSS ORDER. THIS WILL WORK IF API CONNECTION RE-ESTABLISHED, EVEN IF BT HAS STALLED except: pass print('CANCEL STOP LOSS') time.sleep(2) bt_file.reload_write(self) #CREATE SHUTDOWN TRIGGER IN INI FILE FOR PARENT PROGRAM TO RECEIVE time.sleep(2) print('STOPPING BACKTRADER') self.env.runstop() #SHUT DOWN BACKTRADER time.sleep(1) press('enter') #MUST KEEP CURSOR ACTIVE ON THE TERMINAL FOR THIS TO WORK return
PARENT PROGRAM
***FRESH START*** #----- ESTABLISH INI FILE -----# config = configparser.ConfigParser() home = os.path.expanduser('~') #USER DIRECTORY filename = pc + '.ini' if not os.path.exists(home + '/00_config/' + filename): print('CREATING NEW INI FILE') f = open(home + '/00_config/' + filename, 'w') else: print('EXISTING INI FILE') pass myfile = Path(home + '/00_config/' + filename) config.read(myfile) section_00 = pc section_01 = pc + '-01' section_02 = pc + '-02' time.sleep(1) #----- CLEAR INI FILE -----# print('PREPARING INI FILE') with open(myfile,'r+') as s: config.read_file(s) config.remove_section(section_00) config.remove_section(section_01) config.remove_section(section_02) s.seek(0) config.write(s) s.truncate() time.sleep(1) #----- CREATE RELOAD SECTIONS IF THEY DO NOT EXIST -----# try: config.get(section_01, 'override') except: # except configparser.NoSectionError: config.add_section(section_01) #ADD NEW SECTION #CREATE ACCOUNT SECTION IF IT DOES NOT EXIST try: config.get(section_02, 'account') except: # except configparser.NoSectionError: config.add_section(section_02) #CREATE TRADE DATA SECTION IF IT DOES NOT EXIST try: config.get(pc, 'tradeid') except: # except configparser.NoSectionError: config.add_section(pc) #----- RELOAD DEFAULT VALUES -----# config.set(section_01, 'override','0') config.set(section_01, 'reload','0') config.set(section_02, 'account','0') config.write(myfile.open('w')) #----- LOAD CEREBRO -----# cerebro(pc) #LOADS BT ('pc' refers to product code that is passed to BT from the parent) ***LOOP CHECKS ON INI FILE*** while True: #----- CONNECTION FAILURE - RELOAD -----# config.read(myfile) reload_sc = config.get(section_01,'reload') if reload_sc == 'SHUTDOWN': #IF INI FILE SAYS 'SHUTDOWN' (WHICH IS SET BY NOTIFY_STORE), THEN... print('KILL CEREBRO') #use to have a kill.subprocess command in here but it seemed redundant but might be useful if running multiple instances on one machine time.sleep(1) print('RELOAD CEREBRO') time.sleep(2) cerebro(pc) else: pass
BT
***FRESH START*** def __init__(): ini_transfer.reload_read(self) #Loads ini file if self.reload_sc == 'SHUTDOWN': #If reloaded set as'SHUTDOWN' then init with last values, not default ini_transfer.read_restart_data(self) else: vars(self) #This is just a method contain a group of variables
SAMPLE CODE FROM INI_TRANSFER
def read_restart_data(self): args = parse_args() config = configparser.ConfigParser() home = os.path.expanduser('~') myfile = Path(home + '/00_config/' + args.data0 + '.ini') config.read(myfile) #path of your .ini file self.tradeid = config.get(args.data0,'tradeid') self.position_size = float(config.get(args.data0,'position_size')) self.freezebar = float(config.get(args.data0,'freezebar')) self.enter_price = float(config.get(args.data0,'enter_price')) self.retracement = float(config.get(args.data0,'retracement')) self.hitstoploss = int(config.get(args.data0,'hitstoploss')) self.high_2 = float(config.get(args.data0,'high_2')) self.low_2 = float(config.get(args.data0,'low_2')) self.high_3 = float(config.get(args.data0,'high_3')) self.pos_long = int(config.get(args.data0,'pos_long')) self.pos_short = int(config.get(args.data0,'pos_short')) self.stop_position = float(config.get(args.data0,'stop_position')) self.trend_backflip = float(config.get(args.data0,'trend_backflip')) self.trend_exit_trigger = float(config.get(args.data0,'trend_exit_trigger')) self.false_signal = float(config.get(args.data0,'false_signal')) self.RTH = int(config.get(args.data0,'RTH')) self.trend_exit_price = float(config.get(args.data0,'trend_exit_price')) self.break_out_long = float(config.get(args.data0,'break_out_long')) self.break_out_short = float(config.get(args.data0,'break_out_short'))
Perhaps some of this might assist you with new ideas to tackle your problem.
Also appreciate if anyone has ideas on how to improve or simplify this?
Not being from a coding background, I am making this up as I go. No doubt there are more efficient ways of achieving some of the things I am doing.
- Parent program