diff --git a/.screenshot2021-0606_19-25-04-863328.png b/.screenshot2021-0606_19-25-04-863328.png new file mode 100644 index 0000000..84e8bf3 Binary files /dev/null and b/.screenshot2021-0606_19-25-04-863328.png differ diff --git a/broker_manager_gui.py b/broker_manager_gui.py index 633e501..57b3682 100644 --- a/broker_manager_gui.py +++ b/broker_manager_gui.py @@ -3,7 +3,6 @@ import logging import pyautogui import pyperclip -import pytz import time import geometry_2d @@ -13,8 +12,21 @@ logger = logging.getLogger('pyFinance') +def repeater(action): + def repeat_action(*args, **kvargs): + tries = 5 + for k in range(tries): + if action(*args, **kvargs): + logger.debug('Check {} - True'.format(action.__name__)) + return + logger.debug('Check {} - False'.format(action.__name__)) + # при всех неудачных попытках кидаем исключение об ошибке + raise RuntimeError('{} setting error'.format(action.__name__)) + return repeat_action + + class BrokerManagerGui(BrokerManagerInterface): - TRY_COUNT = 3 + TRY_COUNT = 5 def __init__(self, result_handler, config_file): super().__init__(result_handler) @@ -22,17 +34,7 @@ def __init__(self, result_handler, config_file): with open(config_file, 'r') as cf: self.config = json.load(cf) - self.exp_hour_buttons = geometry_2d.get_matrix( - m_size=geometry_2d.Vector(x=6, y=4), - start=geometry_2d.Vector(**self.config['buttons']['expiration_time']['first_hour']), - delta=geometry_2d.Vector(**self.config['buttons']['expiration_time']['delta']) - ) - - self.exp_minute_buttons = geometry_2d.get_matrix( - m_size=geometry_2d.Vector(x=3, y=4), - start=geometry_2d.Vector(**self.config['buttons']['expiration_time']['first_minute']), - delta=geometry_2d.Vector(**self.config['buttons']['expiration_time']['delta']) - ) + self.interval_deal_time = None self.option_buttons = dict(zip( BrokerManagerInterface.OPTION_LIST, @@ -51,17 +53,31 @@ def __init__(self, result_handler, config_file): ] )) + # Устанавливаем начальный опцион + self.current_option = None + try: + self.click_option('EURUSD') + except: + pass + + self.option_buttons['CADCHF'] = self.option_buttons['CADJPY'] + def _get_deal_result(self): self.is_deal = False result = '' windows_manager.activate_window('Прозрачный брокер бинарных опционов') + + # открываем графу сделок "открытые" + pyautogui.doubleClick( + self.config['buttons']['opened']['x'], + self.config['buttons']['opened']['y'], + duration=0.1 + ) + time.sleep(5) + for k in range(BrokerManagerGui.TRY_COUNT): - pyperclip.copy("") # <- Это предотвращает замену последней копии текущей копией null. - pyautogui.doubleClick(self.config['fields']['result']['x'], self.config['fields']['result']['y']) - pyautogui.hotkey('ctrl', 'c') - time.sleep(1) # ctrl-c обычно работает очень быстро, но ваша программа может выполняться быстрее - result = pyperclip.paste() + result = self.get_field('result') if result in ['LOSE', 'WIN']: break time.sleep(5) @@ -69,58 +85,92 @@ def _get_deal_result(self): # If result not in ['LOSE', 'WIN'] return as is self.result_handler(result) + def set_field(self, field, value): + pyautogui.doubleClick( + self.config['fields'][field]['x'], + self.config['fields'][field]['y'], + duration=0.1 + ) + time.sleep(0.5) + pyautogui.write(str(value), interval=0.25) + time.sleep(0.5) + + def get_field(self, field, use_mouse=False): + pyperclip.copy("") # <- Это предотвращает замену последней копии текущей копией null. + + pyautogui.doubleClick( + self.config['fields'][field]['x'], + self.config['fields'][field]['y'], + duration=0.1 + ) + time.sleep(0.5) + + if use_mouse: + pyautogui.rightClick( + self.config['fields'][field]['x'], + self.config['fields'][field]['y'], + duration=0.1 + ) + time.sleep(0.5) + + pyautogui.click( + self.config['fields'][field]['x'] + self.config['context_menu']['copy']['x'], + self.config['fields'][field]['y'] + self.config['context_menu']['copy']['y'], + duration=0.1 + ) + else: + # ctrl-c обычно работает очень быстро, но ваша программа может выполняться быстрее + pyautogui.hotkey('ctrl', 'c') + + time.sleep(0.5) + return pyperclip.paste() + + @repeater + def try_set_field(self, field, value, use_mouse=False): + self.set_field(field, value) + return self.get_field(field, use_mouse) == str(value) + + @repeater + def set_expiration_time(self, finish_datetime): + self.interval_deal_time = int((finish_datetime - datetime.datetime.now()).total_seconds() // 60) + self.set_field('expiration_time', self.interval_deal_time) + return self.get_field('expiration_time') == str(self.interval_deal_time) + + def click_option(self, option): + @repeater + def click_option_button(point, screenshot): + pyautogui.click(point.x, point.y, duration=0.1) + time.sleep(3) + screenshot_new = pyautogui.screenshot(region=(point.x - 5, point.y - 5, point.x + 5, point.y + 5)) + if screenshot == screenshot_new: + return False + self.current_option = option + return True + + if self.current_option == option: + return + + point = self.option_buttons[option] + screenshot = pyautogui.screenshot(region=(point.x - 5, point.y - 5, point.x + 5, point.y + 5)) + + click_option_button(point, screenshot) + + def make_deal(self, option, prognosis, summ, deal_time): if self.is_deal: - logger.info('Deal is active now, skip new deal.') + logger.info('Deal is active now, skip new deal.\n') return windows_manager.activate_window('Прозрачный брокер бинарных опционов') - pyautogui.click(self.option_buttons[option].x, self.option_buttons[option].y, duration=0.1) - time.sleep(2) - for k in range(self.TRY_COUNT): - pyautogui.doubleClick( - self.config['fields']['investment_money']['x'], - self.config['fields']['investment_money']['y'], - duration=0.1 - ) - time.sleep(1) - pyautogui.write(str(summ), interval=0.25) - time.sleep(1) + finish_datetime = datetime.datetime.now() + datetime.timedelta(minutes=deal_time) + + self.click_option(option) + self.try_set_field('investment_money', summ, use_mouse=True) + self.set_expiration_time(finish_datetime) - pyautogui.click( - self.config['fields']['expiration_time']['x'], - self.config['fields']['expiration_time']['y'], - duration=0.1 - ) - time.sleep(2) - pyautogui.click(self.exp_hour_buttons[deal_time.hour].x, self.exp_hour_buttons[deal_time.hour].y, duration=0.1) - time.sleep(2) - pyautogui.click( - self.exp_minute_buttons[deal_time.minute // 5].x, - self.exp_minute_buttons[deal_time.minute // 5].y, - duration=0.1 - ) - time.sleep(2) pyautogui.click(self.prognosis_table[prognosis].x, self.prognosis_table[prognosis].y, duration=0.1) self.is_deal = True - # Set up timer on finish job - msk_tz = pytz.timezone('Europe/Moscow') - now_date = datetime.datetime.now(msk_tz) - finish_datetime = msk_tz.localize( - datetime.datetime( - now_date.year, - now_date.month, - now_date.day, - deal_time.hour, - deal_time.minute - ) - ) - if deal_time.hour in [0, 1]: - finish_datetime += datetime.timedelta(days=1) - finish_datetime = finish_datetime.astimezone() - - logger.debug("finish_datetime={}".format(finish_datetime)) - + finish_datetime = datetime.datetime.now() + datetime.timedelta(minutes=self.interval_deal_time) self.scheduler.add_job(self._get_deal_result, 'date', run_date=finish_datetime) diff --git a/broker_manager_gui_luzin_config.json b/broker_manager_gui_luzin_config.json index 1b6091f..c376f7f 100644 --- a/broker_manager_gui_luzin_config.json +++ b/broker_manager_gui_luzin_config.json @@ -34,6 +34,10 @@ "x": 1250, "y": 340 } + }, + "opened": { + "x": 1213, + "y": 415 } }, @@ -48,7 +52,14 @@ }, "result": { "x": 1330, - "y": 462 + "y": 470 + } + }, + + "context_menu": { + "copy": { + "x": 44, + "y": 85 } } } diff --git a/broker_manager_gui_nick_config.json b/broker_manager_gui_nick_config.json index b3302ba..82fe6a3 100644 --- a/broker_manager_gui_nick_config.json +++ b/broker_manager_gui_nick_config.json @@ -4,11 +4,11 @@ "expiration_time": { "first_hour": { "x": 585, - "y": 219 + "y": 231 }, "first_minute": { "x": 831, - "y": 219 + "y": 231 }, "delta": { "x": 39, @@ -18,7 +18,7 @@ "option": { "first": { "x": 164, - "y": 146 + "y": 159 }, "delta": { "x": 54, @@ -28,27 +28,38 @@ "prognosis": { "call": { "x": 824, - "y": 351 + "y": 363 }, "put": { "x": 944, - "y": 351 + "y": 363 } + }, + "opened": { + "x": 866, + "y": 412 } }, "fields": { "investment_money": { "x": 851, - "y": 156 + "y": 168 }, "expiration_time": { "x": 911, - "y": 156 + "y": 168 }, "result": { - "x": 983, - "y": 457 + "x": 987, + "y": 470 + } + }, + + "context_menu": { + "copy": { + "x": 52, + "y": 91 } } } diff --git a/broker_manager_interface.py b/broker_manager_interface.py index eedfc0f..00358ab 100644 --- a/broker_manager_interface.py +++ b/broker_manager_interface.py @@ -5,7 +5,7 @@ class BrokerManagerInterface: OPTION_LIST = ( 'AUDCAD', 'AUDJPY', 'AUDUSD', 'EURAUD', 'EURCHF', 'EURJPY', 'GBPAUD', 'GBPJPY', 'NZDJPY', 'USDCAD', 'USDJPY', - 'AUDCHF', 'AUDNZD', 'CADJPY', 'EURCAD', 'EURGBP', 'EURUSD', 'GBPCHF', 'GBPNZD', 'NZDUSD', 'USDCHF' + 'AUDCHF', 'AUDNZD', 'CADJPY', 'EURCAD', 'EURGBP', 'EURUSD', 'GBPCHF', 'GBPNZD', 'NZDUSD', 'USDCHF', 'CADCHF' ) PROGNOSIS_LIST = ('вверх', 'вниз') diff --git a/pyFinance_v3_ref.py b/pyFinance_v1_quotex.py similarity index 68% rename from pyFinance_v3_ref.py rename to pyFinance_v1_quotex.py index 004efc8..ca8403f 100644 --- a/pyFinance_v3_ref.py +++ b/pyFinance_v1_quotex.py @@ -8,17 +8,22 @@ from broker_manager_gui import BrokerManagerGui, BrokerManagerInterface +# Cоздание и сохранение пути файла session.sav SAVE_STATE_FILE_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'session.sav') +# Cоздание папки log +if not os.path.isdir("log"): + os.mkdir("log") + # Initial values step = 1 -init_summ = 50 +INIT_SUMM = 50 # Prepare logger logger = logging.getLogger('pyFinance') logger.setLevel(logging.DEBUG) -fh = logging.FileHandler(datetime.datetime.now().strftime('%Y-%m-%d.log'), 'a', 'utf-8') +fh = logging.FileHandler(os.path.join('log', datetime.datetime.now().strftime('%Y-%m-%d.log')), 'a', 'utf-8') formatter = logging.Formatter('%(asctime)s %(message)s') fh.setFormatter(formatter) fh.setLevel(logging.DEBUG) @@ -31,7 +36,7 @@ # Prepare telethon logger telethon_logger = logging.getLogger('telethon') -tfh = logging.FileHandler(datetime.datetime.now().strftime('%Y-%m-%d_telethon.log')) +tfh = logging.FileHandler(os.path.join('log', datetime.datetime.now().strftime('%Y-%m-%d_telethon.log')), 'a', 'utf-8') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') tfh.setFormatter(formatter) telethon_logger.setLevel(logging.DEBUG) @@ -40,54 +45,55 @@ def save_state(save_file_path): global step - global init_summ + global INIT_SUMM with open(save_file_path, 'w') as sav: - sav.write("{} {}".format(step, init_summ)) + sav.write("{} {}".format(step, INIT_SUMM)) - logger.debug("Saved to {}".format(save_file_path)) + logger.debug("Saved to {}\n".format(save_file_path)) def load_state(save_file_path): global step - global init_summ + global INIT_SUMM if not os.path.isfile(save_file_path): - logger.error("Save state {} is not exists".format(save_file_path)) + logger.error("Save state {} is not exists\n".format(save_file_path)) return with open(save_file_path, 'r') as sav: content = sav.read() - step, init_summ = map(int, content.split()) + step, INIT_SUMM = map(int, content.split()) logger.debug("Loaded from {}".format(save_file_path)) logger.debug('step = {}'.format(step)) - logger.debug('init_summ = {}'.format(init_summ)) + logger.debug('init_summ = {}'.format(INIT_SUMM)) def get_summ(st): - return int(init_summ * (2.2 ** (st - 1))) + return int(INIT_SUMM * (2.3 ** (st - 1))) def parse_signal(signal_text): signal_lines = signal_text.split('\n') - if len(signal_lines) < 2: - # Ожидаем как минимум 2 строки, иначе это не сигнал + print(signal_lines) + if len(signal_lines) != 1: + # Ожидаем 1 строку, иначе это не сигнал return None option = signal_lines[0][:6] if option not in BrokerManagerInterface.OPTION_LIST: # Если не нашли известный нам опцион, значит это не сигнал return None - - pattern = r'(вверх|вниз)до(\d{2}.\d{2})мск' - m = re.match(pattern, signal_lines[1].replace(' ', '').lower()) + + pattern = r'[\S\D]*(вверх|вниз)на(\d+)[\S\D]*' + m = re.match(pattern, signal_lines[0].replace(' ', '').lower()) if m is None: - # Если вторая строка не соответствует шаблону, значит это не сигнал + # Если строка не соответствует шаблону, значит это не сигнал return prognosis = m.group(1) deal_time_str = m.group(2) - deal_time = datetime.datetime.strptime(deal_time_str, '%H.%M').time() + deal_time = int(deal_time_str) return option, prognosis, deal_time @@ -100,6 +106,7 @@ def deal_result_process(result): elif result == 'WIN': step = 1 else: + step = 1 logger.error('Unknown result: {}'.format(result)) save_state(SAVE_STATE_FILE_PATH) @@ -108,7 +115,7 @@ def deal_result_process(result): def message_process(message_text, message_date, broker_manager): global step - logger.info('') + logger.info('-------------------------------------------------------------------') logger.info('Got message') logger.debug(message_text) logger.info(message_date.strftime('Message date: %d-%m-%Y %H:%M')) @@ -116,19 +123,20 @@ def message_process(message_text, message_date, broker_manager): try: signal = parse_signal(message_text) if signal is None: - logger.info('Message is not a signal, skip.') + logger.info('Message is not a signal, skip.\n') return option, prognosis, deal_time = signal - logger.info('Получен сигнал: {opt} {prog} до {tm}'.format( + logger.info('Получен сигнал: {opt} {prog} на {tm}'.format( opt=option, prog=prognosis, - tm=deal_time.strftime('%H.%M') + tm=deal_time )) summ = get_summ(step) logger.info('Сумма: {}'.format(summ)) + logger.info('Колено: {}'.format(step)) broker_manager.make_deal(option, prognosis, summ, deal_time) @@ -148,15 +156,16 @@ def main(): client = TelegramClient(number, api_id, api_hash) broker_manager = BrokerManagerGui(deal_result_process, config) - - @client.on(events.NewMessage(chats='Scrooge Club')) # создает событие, срабатывающее при появлении нового сообщения +#🔊 СИГНАЛЫ №1 🔊 + # создает событие, срабатывающее при появлении нового сообщения + @client.on(events.NewMessage(chats='tFinace')) async def normal_handler(event): message = event.message.to_dict() message_process(message['message'], message['date'], broker_manager) load_state(SAVE_STATE_FILE_PATH) client.start() - logger.info('Клиент запущен, бот активен.') + logger.info('Клиент запущен, бот активен.\n') client.run_until_disconnected() diff --git a/tools/get_coord.py b/tools/get_coord.py new file mode 100644 index 0000000..a7a50f3 --- /dev/null +++ b/tools/get_coord.py @@ -0,0 +1,7 @@ +import pyautogui +import time + +while True: + currentMouseX, currentMouseY = pyautogui.position() # Получаем XY координаты курсора. + print(currentMouseX, currentMouseY) + time.sleep(1) diff --git a/tools/limit.py b/tools/limit.py new file mode 100644 index 0000000..f651574 --- /dev/null +++ b/tools/limit.py @@ -0,0 +1,13 @@ +# Python 3 + +summa = float(input('введите первоночальную сумму = ')) +k = float(input('введите коэффициент мартина = ')) +step = int(input('введите кол-во колен = ')) +i=1 +s=0 + +for i in range(step): + a = int(summa * (k ** (i))) + print('колено №{} = {}'.format(i, a)) + s = s + a +print('общая сумма = ', s)