├── .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 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/binarybot.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
--------------------------------------------------------------------------------