notify_store : Create Events when Connection Failed
-
WORKING
I have setup notify_store to clear stop orders when I manually close a position using the brokers platform. This works.NOT WORKING
I want to send close positions and open orders when a connection has failed. I often found that the system continues to send orders after a time out even through BT has stopped. This can result in accumulated positions.When either a 'Connection Failed' or 'Timed Out' is received by notify_store, I'd like to run through the process shown below:
- read my *.ini file to find position size prior to connection issue
- send a close order
- send a cancel stop loss
- write to *.ini file to signal connection failed
- runstop
I've test the sequence above by placing it under
if 'external transaction MARKET_ORDER' in msg:
and it works. It reads ini file, closes positions, writes ini file and then reloads cerebro as a subprocess in the parent program. However, when it is placed inif 'V20ConnectionError' in msg:
orif 'timed out' in msg:
I receive the following error:if 'external transaction MARKET_ORDER' in msg: TypeError: argument of type 'V20ConnectionError' is not iterable
Is this not possible, or does it need to be used as a callback (which I'm not familiar using)?
Appreciate any thoughts you have.
NOTIFY_STORE CODE:
def notify_store(self, msg, *args, **kwargs): print('*' * 5, 'STORE NOTIF:', msg) ### IF MANUAL CLOSE TRADE VIA PLATFORM, THEN CANCEL STOP LOSS --- THIS WORKS if 'external transaction MARKET_ORDER' in msg: print('msg = external transaction') 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') return ### CONNECTION FAILED --- THIS DOES NOT WORK if 'V20ConnectionError' in msg: print('CONNECTION FAILED') #READ INI FILE TO GET POSTION SIZE bt_file.read_trade_ini(self) print('TRY TO CLOSE POSITION') self.close(size=self.position_size) print('POSITION CLOSED. TRY TO CANCEL STOP LOSS') self.cancel(self.stop_ord) print('CANCEL STOP LOSS') bt_file.reload_write(self) #CREATE SHUTDOWN & RELOAD TRIGGER IN INI FILE print('STOPPING BACKTRADER') self.env.runstop() press('enter') return if 'timed out' in msg: ### TIMED OUT --- THIS DOES NOT WORK print('TIMED OUT') #READ INI FILE TO GET POSTION SIZE bt_file.read_trade_ini(self) print('TRY TO CLOSE POSITION') self.close(size=self.position_size) print('POSITION CLOSED. TRY TO CANCEL STOP LOSS') self.cancel(self.stop_ord) print('CANCEL STOP LOSS') bt_file.reload_write(self) #CREATE SHUTDOWN & RELOAD TRIGGER IN INI FILE print('STOPPING BACKTRADER') self.env.runstop() press('enter') return
-
SOLVED
Never underestimate the power of perseverance.
The following is my modified
notify_store()
. This is tested with OANDA.What it does:
-
If a manual trade occurs via the broker platform with 'external transaction MARKET_ORDER' then try to cancel stop_loss if one exists.
-
All other notify_store errors:
- Try to send sms alert (using Twillio account) with error to my mobile
- Get position size from my *ini file (Note: on each cycle through
next()
I store critical system/trade data in an *.ini file). Position is queried from *.ini instead of broker because connection may not allow getting position from broker - Try close order with position size
- Try cancel stop loss
- Write SHUTDOWN signal to *ini file to let parent program know BT has failed
- Stop BT
-
The parent program will see that BT (as a subprocess) has failed and shut down. It will kill the BT subprocess and reload it.
-
BT reloads and during
__init__
looks to see if there is already existing system/trade data in the *.ini file. If True then the old system/trade data is reloaded, otherwise a fresh start is required.
import backtrader as bt import signal from keyboard import press from actions.sms_send import SendSMS from ini.ini_reader import bt_file def notify_store(self, msg, *args, **kwargs): print('*' * 5, 'STORE NOTIF:', msg) if 'external transaction MARKET_ORDER' in msg: print('msg = external transaction') try: cancel = self.cancel(self.stop_ord) #CANCEL STOP LOSS print('CANCEL STOP LOSS') return except AttributeError: print('NO STOP LOSS TO CANCEL') returnsdg else: print('NOT SURE IF STOP LOSS CURRENTLY OPEN') message = SendSMS.client.messages.create( from_='+xxxxxxxxxx', to='+xxxxxxxxxx', body=('FAILED TO CANCEL STOP LOSS: CHECK ON PLATFORM')) return else: print('CONNECTION FAILED') print('SEND SMS') try: message = SendSMS.client.messages.create( from_='+xxxxxxxxxx', to='+xxxxxxxxxx', body=('SHUT DOWN: CLOSING POSITIONS & RELOADING: {}'.format(msg))) except: pass print('SMS SENT') print('GET POSITION SIZE FROM INI FILE') time.sleep(2) #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(2) 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/RELOAD TRIGGER IN INI FILE FOR PARRENT PROGRAM TO RECEIVE time.sleep(2) print('STOPPING BACKTRADER') self.env.runstop() #SHUT DOWN BACKTRADER press('enter') return #EXIT BACKTRADER
What other ideas have people used to deal with connection failures?
-