├── .gitignore ├── .DS_Store ├── __pycache__ ├── logs.cpython-37.pyc ├── configs.cpython-37.pyc └── iqoption.cpython-37.pyc ├── .idea ├── vcs.xml ├── .gitignore ├── inspectionProfiles │ └── profiles_settings.xml ├── modules.xml ├── misc.xml └── binarybot.iml ├── README.md ├── logs.py ├── trades.csv ├── configs.py ├── bot.py └── iqoption.py /.gitignore: -------------------------------------------------------------------------------- 1 | trades.csv 2 | Logs/* -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpuggian/binarybot/HEAD/.DS_Store -------------------------------------------------------------------------------- /__pycache__/logs.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpuggian/binarybot/HEAD/__pycache__/logs.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/configs.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpuggian/binarybot/HEAD/__pycache__/configs.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/iqoption.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpuggian/binarybot/HEAD/__pycache__/iqoption.cpython-37.pyc -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/binarybot.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Binarybot 2 | 3 | A trader bot to automate a trade execution scheduling it at IQoption.com 4 | 5 | ## How to schedule your trades? 6 | 7 | All trades are scheduleds using a CSV in the following format: 8 | 9 | | ACTIVE | BUY TIME | ACTION | VALUE | 10 | |---------|----------|--------|-------| 11 | | EUR/USD | 09:31 | PUT | 2 | 12 | 13 | 14 | ## Usage 15 | 16 | After fill the csv with your trades, run the bot using: 17 | 18 | ``` 19 | python bot.py 20 | ``` 21 | 22 | Bot will ask to type all needed information and your IQoption credentials to start. 23 | -------------------------------------------------------------------------------- /logs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | import logging 4 | 5 | 6 | class Logs: 7 | def __init__(self): 8 | super().__init__() 9 | self.create_folder() 10 | self.build_files() 11 | 12 | @staticmethod 13 | def print_message(message): 14 | logging.info(message) 15 | print(message) 16 | 17 | @staticmethod 18 | def print_error(message): 19 | logging.error(message) 20 | print(message) 21 | 22 | @staticmethod 23 | def create_folder(): 24 | if not os.path.exists("Logs/"): 25 | os.mkdir("Logs") 26 | 27 | @staticmethod 28 | def build_files(): 29 | file = "Logs/{}.log".format( 30 | datetime.datetime.now().strftime("%d-%m-%Y")) 31 | format = "%(asctime)s %(levelname)s: %(message)s" 32 | date = "%d-%m-%Y %H:%M:%S" 33 | logging.basicConfig(filename=file, level=logging.INFO, 34 | format=format, datefmt=date) 35 | -------------------------------------------------------------------------------- /trades.csv: -------------------------------------------------------------------------------- 1 | ATIVO,ENTRADA,ACTION,VALOR 2 | EUR/USD,00:10,CALL,12.50 3 | GBP/JPY,06:45,CALL,12.50 4 | AUD/USD,00:00,PUT,12.50 5 | GBP/JPY,00:15,PUT,12.50 6 | EUR/AUD,00:30,PUT,12.50 7 | USD/CHF,01:15,PUT,12.50 8 | AUD/JPY,01:30,PUT,12.50 9 | EUR/AUD,02:00,PUT,12.50 10 | EUR/USD,02:45,PUT,12.50 11 | GBP/CAD,03:00,PUT,12.50 12 | EUR/NZD,03:15,PUT,12.50 13 | USD/CAD,03:30,PUT,12.50 14 | GBP/CHF,04:00,PUT,12.50 15 | AUD/USD,04:30,PUT,12.50 16 | GBP/CAD,05:00,PUT,12.50 17 | USD/JPY,05:30,PUT,12.50 18 | GBP/AUD,06:00,PUT,12.50 19 | EUR/AUD,06:30,PUT,12.50 20 | EUR/CAD,07:00,PUT,12.50 21 | USD/CAD,07:15,PUT,12.50 22 | GBP/JPY,07:45,PUT,12.50 23 | EUR/CAD,08:15,PUT,12.50 24 | EUR/AUD,08:45,PUT,12.50 25 | EUR/JPY,09:15,PUT,12.50 26 | EUR/NZD,09:45,PUT,12.50 27 | AUD/JPY,10:15,PUT,12.50 28 | EUR/AUD,10:45,PUT,12.50 29 | USD/JPY,11:15,PUT,12.50 30 | GBP/JPY,11:45,PUT,12.50 31 | AUD/JPY,12:45,PUT,12.50 32 | GBP/AUD,13:15,PUT,12.50 33 | AUD/JPY,14:00,PUT,12.50 34 | GBP/CAD,14:30,PUT,12.50 35 | USD/CAD,14:45,PUT,12.50 36 | EUR/CAD,15:00,PUT,12.50 -------------------------------------------------------------------------------- /configs.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | class Configuracoes: 4 | def __init__(self): 5 | super().__init__() 6 | 7 | def setAtivo(self, ativo): 8 | if len(ativo) <= 0: 9 | logging.error("Ativo nao reconhecido") 10 | return False 11 | else: 12 | logging.info("Ativo definido como {}".format(str(ativo))) 13 | self.ativo=ativo 14 | return True 15 | 16 | def getAtivo(self): 17 | return self.ativo 18 | 19 | def setTimeframe(self, timeframe): 20 | try: 21 | timeframe=int(timeframe) 22 | except: 23 | logging.error("Timeframe nao reconhecido") 24 | return False 25 | if isinstance(timeframe, int): 26 | if int(timeframe) == 5 or int(timeframe) == 1: 27 | logging.info( 28 | "Timeframe definido para {} minutos".format(str(timeframe))) 29 | self.timeframe=timeframe 30 | return True 31 | else: 32 | logging.error("O timeframe pode ser apenas de 1 ou 5 minutos") 33 | return False 34 | else: 35 | logging.error("Timeframe nao reconhecido") 36 | return False 37 | 38 | def getTimeframe(self): 39 | return self.timeframe 40 | 41 | def setPosicao(self, posicao): 42 | try: 43 | posicao=int(posicao) 44 | except: 45 | logging.error("Posicao nao reconhecido") 46 | return False 47 | if isinstance(posicao, int): 48 | self.posicao=posicao 49 | logging.info("Posicao definida para {}".format(str(posicao))) 50 | return True 51 | else: 52 | logging.error("Posicao nao reconhecido") 53 | return False 54 | 55 | def getPosicao(self): 56 | return self.posicao -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | import schedule 4 | from logs import Logs 5 | from iqoption import IQOption 6 | from configs import Configuracoes 7 | import csv 8 | import threading 9 | from iqoptionapi.stable_api import IQ_Option 10 | import time 11 | import threading 12 | 13 | 14 | logs = Logs() 15 | 16 | 17 | def run_threaded(job_func): 18 | job_thread = threading.Thread(target=job_func) 19 | job_thread.start() 20 | 21 | def login(api): 22 | conectado, _ = api.connect() 23 | if not conectado: 24 | logs.print_error("Error on login.") 25 | return False 26 | else: 27 | return True 28 | 29 | 30 | def add_option(ativo, startTime, direcao, entrada, stop_loss, stop_win, api, original_balance): 31 | configuracao = Configuracoes() 32 | configuracao.setAtivo(ativo) 33 | configuracao.setTimeframe(5) 34 | IQ = IQOption(api) 35 | IQ.setDirecao(direcao) 36 | IQ.definirConfiguracoes(configuracao.getAtivo(), configuracao.getTimeframe(), 1) 37 | IQ.set_original_balance(original_balance) 38 | IQ.set_stop_win(stop_win) 39 | IQ.set_stop_loss(stop_loss) 40 | IQ.setEntrada(entrada) 41 | schedule.every().day.at(startTime).do(run_threaded, IQ.buy) 42 | logs.print_message("Trade programmed: paper:{}, exp:{}, action:{}, value:{} ✅".format(ativo, startTime, direcao, entrada)) 43 | 44 | 45 | def main(): 46 | logs.print_message("Bot Started!") 47 | 48 | #login 49 | logs.print_message("Login Credentials IQ Option:") 50 | email = input("Email:") 51 | password = input("Pass:") 52 | api = IQ_Option(email, password) 53 | if not login(api): 54 | logs.print_error("Error on try to login. Check iq option credentials on environment variables.") 55 | exit() 56 | logs.print_message("Conected: IQ Option!") 57 | 58 | #stops 59 | #REAL / PRACTICE 60 | account_type = input("Set the account type (REAL or PRACTICE):") 61 | api.change_balance(account_type) 62 | original_balance = api.get_balance() 63 | logs.print_message("Original balance: $ {}".format(original_balance)) 64 | stop_loss = input("Set a stop loss value:") 65 | stop_win = input("Set a stop win value:") 66 | 67 | #read trades 68 | f = open("trades.csv") 69 | csv_f = csv.reader(f) 70 | counter = 0 71 | for row in csv_f: 72 | if counter == 0: 73 | logs.print_message("Programming Orders...") 74 | else: 75 | start_time = datetime.datetime.strptime(row[1], '%H:%M') 76 | time_result = start_time - datetime.timedelta(seconds=15) 77 | add_option(row[0].replace('/', ''), time_result.strftime("%H:%M:%S"), row[2], row[3], stop_loss, stop_win, api, original_balance) 78 | counter = counter + 1 79 | 80 | logs.print_message("\nProcessing Orders...") 81 | 82 | while True: 83 | schedule.run_pending() 84 | time.sleep(1) 85 | 86 | 87 | if __name__ == "__main__": 88 | main() 89 | -------------------------------------------------------------------------------- /iqoption.py: -------------------------------------------------------------------------------- 1 | import schedule 2 | import logging 3 | from logs import Logs 4 | 5 | logs = Logs() 6 | 7 | 8 | class IQOption: 9 | def __init__(self, api): 10 | super().__init__() 11 | self.api = api 12 | 13 | def definirConfiguracoes(self, ativo, timeframe, posicao): 14 | self.ativo = ativo 15 | self.timeframe = int(timeframe) 16 | self.posicao = int(posicao) 17 | 18 | def checarAtivo(self, ativo): 19 | ativos = self.api.get_all_open_time() 20 | if ativos["digital"][ativo]["open"]: 21 | logging.info("Ativo encontrado") 22 | return True 23 | else: 24 | logging.error("O ativo {} nao foi encontrado".format(str(ativo))) 25 | print("O ativo {} nao foi encontrado".format(str(ativo))) 26 | return False 27 | 28 | def contaReal(self): 29 | self.api.change_balance("REAL") 30 | 31 | def contaDemo(self): 32 | self.api.change_balance("PRACTICE") 33 | 34 | def pegarSaldo(self): 35 | return self.api.get_balance() 36 | 37 | def pegarMoeda(self): 38 | return self.api.get_currency() 39 | 40 | def setDirecao(self, direcao): 41 | self.direcao = direcao 42 | 43 | def set_original_balance(self, balance): 44 | self.original_balance = balance 45 | 46 | def setEntrada(self, entrada): 47 | try: 48 | entrada = float(entrada) 49 | except: 50 | logging.error("Nao foi possivel definir o preco de entrada") 51 | return False 52 | if isinstance(entrada, float): 53 | self.entrada = entrada 54 | return True 55 | else: 56 | logging.error("Nao foi possivel definir o preco de entrada") 57 | return False 58 | 59 | def set_stop_win(self, stop_win): 60 | try: 61 | stop_win = float(stop_win) 62 | except: 63 | logging.error("Nao foi possivel definir o preco de stop_win") 64 | return False 65 | if isinstance(stop_win, float): 66 | self.stop_win = stop_win 67 | return True 68 | else: 69 | logging.error("Nao foi possivel definir o preco de stop_win") 70 | return False 71 | 72 | def set_stop_loss(self, stop_loss): 73 | try: 74 | stop_loss = float(stop_loss) 75 | except: 76 | logging.error("Nao foi possivel definir o preco de stop_loss") 77 | return False 78 | if isinstance(stop_loss, float): 79 | self.stop_loss = stop_loss 80 | return True 81 | else: 82 | logging.error("Nao foi possivel definir o preco de stop_loss") 83 | return False 84 | 85 | def check_trade_result(self, order_id): 86 | result = self.api.check_win_v3(order_id) 87 | if result < 0: 88 | logs.print_message( 89 | "LOST: paper:{}, action:{}, value:{} ❌".format(self.ativo, self.direcao, self.entrada)) 90 | else: 91 | logs.print_message( 92 | "WIN: paper:{}, action:{}, value:{} ✅".format(self.ativo, self.direcao, self.entrada)) 93 | return result 94 | 95 | 96 | def execute_martingale(self): 97 | balance = self.pegarSaldo() 98 | self.check_stops(balance) 99 | 100 | self.entrada = self.entrada * 2 101 | logs.print_message("Initializing Martingale paper:{}, action:{}, value:{}".format(self.ativo, 102 | self.direcao, 103 | self.entrada)) 104 | 105 | logs.print_message( 106 | "Executing programmed trade, paper:{}, action:{}, value:{}, exp:{}min".format(self.ativo, 107 | self.direcao, 108 | self.entrada, 109 | self.timeframe)) 110 | _, gale_order_id = self.api.buy( self.entrada, self.ativo, self.direcao, self.timeframe) 111 | result = self.check_trade_result(gale_order_id) 112 | if result < 0: 113 | self.entrada = self.entrada * 2 114 | logs.print_message("Initializing Martingale 2 paper:{}, action:{}, value:{}".format(self.ativo, 115 | self.direcao, 116 | self.entrada)) 117 | 118 | logs.print_message( 119 | "Executing programmed trade mg2, paper:{}, action:{}, value:{}, exp:{}min".format(self.ativo, 120 | self.direcao, 121 | self.entrada, 122 | self.timeframe)) 123 | _, gale2_order_id = self.api.buy( self.entrada, self.ativo, self.direcao, self.timeframe) 124 | self.check_trade_result(gale2_order_id) 125 | 126 | 127 | 128 | def check_stops(self, balance): 129 | if balance <= self.stop_loss: 130 | logs.print_message("Stop loss reached, no trading more today. ❌") 131 | exit() 132 | 133 | if balance >= self.stop_win: 134 | logs.print_message("Stop win reached, no trading more today. ❌") 135 | exit() 136 | 137 | 138 | def buy(self): 139 | balance = self.pegarSaldo() 140 | self.check_stops(balance) 141 | 142 | if self.checarAtivo(self.ativo): 143 | try: 144 | logs.print_message( 145 | "Executing programmed trade, paper:{}, action:{}, value:{}, exp:{}min".format(self.ativo, 146 | self.direcao, 147 | self.entrada, 148 | self.timeframe)) 149 | _, order_id = self.api.buy(self.entrada, self.ativo, self.direcao, self.timeframe) 150 | result = self.check_trade_result(order_id) 151 | if result < 0: 152 | self.execute_martingale() 153 | 154 | except: 155 | import traceback 156 | logs.print_error("Error on execute order. paper:{}, action:{}, value:{}".format(self.ativo, 157 | self.direcao, 158 | self.entrada)) 159 | logging.error(traceback.format_exc()) 160 | logs.print_message("New balance: ${}".format(self.pegarSaldo())) 161 | schedule.CancelJob 162 | logs.print_message("\nProcessing Orders...") 163 | exit() 164 | --------------------------------------------------------------------------------