bot.send_message( chat, f"Ngrok is already running and available at {ngrok.get_public_url()}" ) else: bot.send_message( chat, "To start the ngrok instance, please enter your totp code:" ) expecting_authentication = True elif text == "/stop": if ngrok.is_running(): ngrok.stop() bot.send_message(chat, "The ngrok instance has been stopped.") else: bot.send_message(chat, "Ngrok is not running.") if env.get("TELEGRAM_BOT_TOKEN"): bot_owner = int(env["TELEGRAM_BOT_OWNER"]) telegram_bot = TelegramBot(env["TELEGRAM_BOT_TOKEN"]) telegram_bot.send_message( bot_owner, f"{hostname} is now up and running. Type /start to forward port {ngrok.port} via ngrok." ) telegram_bot.run(on_update) else: print(ngrok.start()) while True: time.sleep(1)
class StateMachine: def __init__(self): self.authorized = False self.ticks_history_received = False self.ticks_subscribed = False self.balance_subscribed = False self.in_deal = False self.symbols_showed = False #self.strategy = 'random' self.strategy = 'bollinger' self.account = {} self.balance = {} self.step = 1 self.loose_counter = 0 self.last_update = time.time() self.telegram = TelegramBot(token=TELEGRAM_TOKEN, proxies={'http': TELEGRAM_PROXY, 'https': TELEGRAM_PROXY}, chat_id=TELEGRAM_CHAT_ID) self.max_loose = 5 self.max_ticks = 100 self.max_timeout = 1200 self.symbol = 'R_50' # При смене контракта все надо обнулить (методом) self.min_bet = 0.35 #self.symbol = 'frxEURUSD' #self.min_bet = 0.50 self.ticks_data = [] self.deals_data = [] self.bollinger_bands_steps = 20 self.standard_deviations = 2 self.token = BOT_TOKEN self.config = {} # Настройки для игры def auth(self): """Авторизация""" return json.dumps({ 'authorize': self.token, }) def ping(self): """Пинг для поддержания соединения""" return json.dumps({ 'ping': 1 }) def get_active_symbols(self): return json.dumps({ 'active_symbols': 'brief', 'product_type': 'basic', }) def get_ticks_history(self) -> str: """Получить историю по тикам""" return json.dumps({ 'ticks_history': self.symbol, 'end': 'latest', 'start': 1, 'style': 'ticks', 'adjust_start_time': 1, 'count': self.max_ticks, }) def subscribe_ticks(self): """Подписаться на обновления тиков потоком""" return json.dumps({ 'ticks': self.symbol, 'subscribe': 1, }) def subscribe_balance(self): """Подписаться на обновления баланса потоком""" return json.dumps({ 'balance': 1, 'account': 'current', 'subscribe': 1, }) def save_new_ticks(self, symbol: str, history: list): """Записываем массив тиков""" if not symbol == self.symbol: logger.error('[ERROR]: symbol %s is incorrect, we wanna %s' % (symbol, self.symbol)) return self.ticks_data = [] self.deals_data = [] if not history: return for i, item in enumerate(history['prices']): tick = { 'symbol': symbol, 'quote': item, 'epoch': history['times'][i], } self.save_new_tick(tick, with_pop = False) def save_new_tick(self, tick: dict, with_pop: bool = True): """Сохранение в массив нового тика :param tick: тик :param with_pop: Удалить первый тик""" if not tick['symbol'] == self.symbol: logger.error('[ERROR]: symbol %s is incorrect, we wanna %s' % (tick['symbol'], self.symbol)) return self.ticks_data.append([tick['epoch'], tick['quote']]) if with_pop: self.ticks_data.pop(0) # Докидываем боллинджера в тик # третий элемент массива в # каждом тике со словарем prices = [item[1] for item in self.ticks_data] for i, cur_tick in enumerate(self.ticks_data): if len(cur_tick) < 3: # Линии болленджера # top, middle, bottom bb = MathOperations.bollinger_bands(prices, i, self.bollinger_bands_steps, self.standard_deviations) cur_tick.append(bb) def playboy(self, reverse: bool = False): """Играем по настройкам Покупка => Цена пересекает среднюю линию канала Боллинджера или касается ее После этого касается крайней линии канала Боллинджера + Покупка делается противоположно :param reverse: для реверсивной покупки""" # Ищем по контракту последнюю сделку, # от нее считать будем strategy = self.config.get('strategy') if strategy == 1: self.strategy = 'bollinger' elif strategy == 2: self.strategy = 'random' else: self.strategy = '' CALL = 'CALL' PUT = 'PUT' if reverse: CALL = 'PUT' PUT = 'CALL' # Случайная стратегия, просто для проверки if self.strategy == 'random': types = (CALL, PUT) return self.buy_from_playboy(types[random.randint(0, len(types)-1)]) elif self.strategy == 'bollinger': result = strategy_opposite_touches(self.ticks_data) if result['action']: return self.buy_from_playboy(result['action']) def buy_from_playboy(self, direction): """Делаем ставку, что там по мартингейлу?""" self.in_deal = True self.last_update = time.time() amount = self.calc_rates() return json.dumps({ 'price': amount, 'buy': 1, 'subscribe': 1, 'parameters': { 'contract_type': direction, 'symbol': self.symbol, 'duration_unit': 't', 'duration': 5, 'basis': 'stake', 'currency': 'USD', 'amount': amount, } }) def calc_rates(self): digit = self.min_bet #0.35 multiply = 2 # Если умудрились max раз подряд всрать пишем в статистику #if self.step > self.stats_data.max_loose_in_sequence: # self.stats_data.max_loose_in_sequence = self.step while self.step > self.max_loose: self.step = self.step - self.max_loose result = MathOperations.martingail(digit, self.step, multiply) return round(result, 2) def follow_deal(self, deal): """Следим за сделкой - правильно ее закрываем :param deal: новая информация о сделке""" for i in range(len(self.deals_data)): if self.deals_data[i]['contract_id'] == deal['contract_id']: self.deals_data[i] = deal transactions = deal.get('transaction_ids') if 'sell' in transactions: self.in_deal = False profit = deal['profit'] if profit < 0: self.step += 1 self.loose_counter += 1 else: self.step = 1 self.loose_counter = 0 msg = '%s %s, profit %s, balance %s' % (BOT_TOKEN, deal.get('status'), profit, self.balance.get('balance')) logger.info(msg) self.telegram.send_message(msg) self.make_deal_report() # отчет по сделкам def make_deal_report(self): """Создать отчет через plotly, отправить сообщение в телегу """ output_img = save_with_plotly(ticks=self.ticks_data, image='png') with open(output_img, 'rb') as f: self.telegram.send_photo(f) if output_img.endswith('.png'): os.unlink(output_img) def refresh(self): """Мягкий перезапуск""" self.authorized = False self.ticks_history_received = False self.ticks_subscribed = False self.balance_subscribed = False self.account = {} self.ticks_data = [] # TODO: если мы были в сделке обыграть if self.in_deal and self.deals_data: logger.info('[IN DEAL]: %s' % (json_pretty_print(self.deals_data.pop()))) self.in_deal = False self.last_update = time.time() logger.info('[REFRESH STATE MACHINE]') def check_pulse(self): """Проверить, что обновления идут""" if time.time() - self.last_update > self.max_timeout: return False return True def set_settings(self, obj: dict = None): """Очищаем настройки по стратегии""" if not obj: # Была стратегия (остановка) if self.config.get('strategy', '') != '': self.telegram.send_message('Закончил играть!') self.config['strategy'] = '' if 'start' in self.config: del self.config['start'] if 'end' in self.config: del self.config['end'] else: # Не было стратегии (запуск) if self.config.get('strategy', '') == '': self.telegram.send_message('Начал играть!') # Была стратегии и сменилась elif self.config.get('strategy', '') != obj.get('strategy'): self.telegram.send_message('Сменил стратегию!') self.config.update(obj) def update_settings(self, interval: int = 10): """Обновить настройки, делаем раз в interval тиков""" last_update = self.config.get('last_update', interval) last_update += 1 if last_update > interval: try: self.config['last_update'] = 0 urla = '%s/binary_com/get_schedule/' % API_URL r = requests.get(urla, params={ 'token': BOT_TOKEN, }) resp = r.json() if resp: self.set_settings(resp) else: self.set_settings() except Exception: self.set_settings() err = 'Не удалось получить настройки' logger.exception(err) self.telegram.send_message(err) return self.config['last_update'] = last_update
class SpeechAssistant(Configuration): def __init__(self, masters_name, assistants_name): super().__init__() self.master_name = masters_name self.assistant_name = assistants_name self.sleep_assistant = False self.not_available_counter = 0 self.recognizer = sr.Recognizer() # let's override the dynamic threshold to 4000, # so the timeout we set in listen() will be used self.recognizer.dynamic_energy_threshold = True self.recognizer.energy_threshold = 4000 self.skill = SkillsLibrary(self, self.master_name, self.assistant_name) self.speaker = None self.restart_request = False self.bot = None self.bot_command = None self.init_bot() def Log(self, exception_title="", ex_type=logging.ERROR): log_data = "" if ex_type == logging.ERROR or ex_type == logging.CRITICAL: (execution_type, message, tb) = sys.exc_info() f = tb.tb_frame lineno = tb.tb_lineno fname = f.f_code.co_filename.split("\\")[-1] linecache.checkcache(fname) target = linecache.getline(fname, lineno, f.f_globals) line_len = len(str(message)) + 10 log_data = f"{exception_title}\n{'File:'.ljust(9)}{fname}\n{'Target:'.ljust(9)}{target.strip()}\n{'Message:'.ljust(9)}{message}\n{'Line:'.ljust(9)}{lineno}\n" log_data += ("-" * line_len) else: log_data = exception_title if ex_type == logging.ERROR or ex_type == logging.CRITICAL: print("-" * 23) print(f"{self.RED} {exception_title} {self.COLOR_RESET}") print("-" * 23) if ex_type == logging.DEBUG: logger.debug(log_data) elif ex_type == logging.INFO: logger.info(log_data) elif ex_type == logging.WARNING: logger.warning(log_data) elif ex_type == logging.ERROR: logger.error(log_data) elif ex_type == logging.CRITICAL: logger.critical(log_data) def listen_to_audio(self, ask=None): voice_text = "" listen_timeout = 3 phrase_limit = 10 if self.isSleeping(): listen_timeout = 2 phrase_limit = 5 # adjust the recognizer sensitivity to ambient noise # and record audio from microphone with sr.Microphone() as source: if not self.isSleeping(): self.recognizer.adjust_for_ambient_noise(source, duration=0.5) try: # announce/play something before listening from microphone if ask: self.speak(ask) if self.bot_command and "/" not in self.bot_command: voice_text = self.bot_command else: # listening audio = self.recognizer.listen( source, timeout=listen_timeout, phrase_time_limit=phrase_limit) # try convert audio to text/string data voice_text = self.recognizer.recognize_google(audio) self.not_available_counter = 0 except sr.UnknownValueError: self.Log( f"{self.assistant_name} could not understand what you have said.", logging.WARNING) if self.isSleeping() and self.not_available_counter >= 3: message = f"\"{self.assistant_name}\" is active again." # print(message) # self.respond_to_bot(message) self.not_available_counter = 0 return voice_text except sr.RequestError: self.not_available_counter += 1 if self.not_available_counter == 3: message = f"\"{self.assistant_name}\" Not Available." self.Log(message) # self.respond_to_bot(message) if self.isSleeping() and self.not_available_counter >= 3: message = f"{self.assistant_name}: reconnecting..." print(message) self.respond_to_bot(message) except gTTSError: self.Log("Exception occurred in speech service.") except Exception as ex: if "listening timed out" not in str(ex): # bypass the timed out exception, (timeout=3, if total silence for 3 secs.) self.Log("Exception occurred while analyzing audio.") if not self.isSleeping() and voice_text.strip(): print( f"{self.BLACK_GREEN}{self.master_name}:{self.GREEN} {voice_text}" ) if not self.isSleeping() and not self.bot_command and voice_text.strip( ): self.respond_to_bot(f"(I heared) YOU: \"{voice_text}\"") if voice_text.strip(): self.bot.last_command = None return voice_text.strip() def sleep(self, value): self.sleep_assistant = value def isSleeping(self): return self.sleep_assistant def init_bot(self): try: self.bot = TelegramBot() self.bot_command = None if check_connection(): poll_thread = Thread(target=self.poll_bot) poll_thread.setDaemon(True) poll_thread.start() bot_command_thread = Thread(target=self.handle_bot_commands) bot_command_thread.setDaemon(True) bot_command_thread.start() except Exception: self.Log("Error while initiating telegram bot.") time.sleep(5) self.restart_request = True self.init_bot() def respond_to_bot(self, audio_string): # don't send response to bot with audio_string containing "filler" p hrases. if not is_match( audio_string, ["I'm here...", "I'm listening...", "(in mute)", "listening..."]): audio_string = audio_string.replace(f"{self.assistant_name}:", "") self.bot.send_message(audio_string) def poll_bot(self): while True: try: self.bot.poll() except Exception: self.Log( "Exception occurred while polling bot, trying to re-connect..." ) time.sleep(5) continue def handle_bot_commands(self): while True: try: # get the latest command from bot self.bot_command = self.bot.last_command # handles the RESTAR command sequece of virtual assistant application if self.bot_command and "/restart" in self.bot_command: self.bot_command = f"restart {self.assistant_name}" # lower the volume of music player (if it's currently playing) # so listening microphone will not block our bot_command request self.skill.music_volume(30) # set the restart flag to true self.restart_request = True break elif self.bot_command: # lower the volume of music player (if it's currently playing) # so listening microphone will not block our bot_command request self.skill.music_volume(30) # let's use a wakeup command if she's sleeping. if self.isSleeping(): self.bot_command = f"hey {self.assistant_name} {self.bot_command}" time.sleep(0.5) except Exception: self.Log("Error while handling bot commands.") self.restart_request = True time.sleep(5) continue def speak(self, audio_string, start_prompt=False, end_prompt=False, mute_prompt=False): if audio_string.strip(): try: # volume up the music player, if applicable self.skill.music_volume(30) force_delete = False # init google's text-to-speech module tts = gTTS(text=audio_string, lang="en", tld="com", lang_check=False, slow=False) # make sure we're in the correct directory of batch file to execute os.chdir(self.ASSISTANT_DIR) if not os.path.isdir(self.AUDIO_FOLDER): os.mkdir(self.AUDIO_FOLDER) # generate a filename for the audio file generated by google audio_file = f"{self.AUDIO_FOLDER}/assistants-audio-{str(random.randint(1, 1000))}.mp3" if start_prompt and "<start prompt>" in audio_string: audio_file = f"{self.AUDIO_FOLDER}/start prompt.mp3" elif start_prompt and audio_string: tts.save(audio_file) sound.playsound(f"{self.AUDIO_FOLDER}/start prompt.mp3") print( f"{self.BLACK_CYAN}{self.assistant_name}:{self.CYAN} {audio_string}" ) # respond to bot as well self.respond_to_bot(audio_string) force_delete = True elif end_prompt: audio_file = f"{self.AUDIO_FOLDER}/end prompt.mp3" elif mute_prompt: audio_file = f"{self.AUDIO_FOLDER}/mute prompt.mp3" else: tts.save(audio_file) print( f"{self.BLACK_CYAN}{self.assistant_name}:{self.CYAN} {audio_string}" ) # respond to bot as well self.respond_to_bot(audio_string) # announce/play the generated audio sound.playsound(audio_file) if not start_prompt and not end_prompt and not mute_prompt or force_delete: # delete the audio file after announcing to save mem space os.remove(audio_file) except Exception as ex: if not ("Cannot find the specified file." or "Permission denied:") in str(ex): self.Log("Exception occurred while trying to speak.") message = f"\"{self.assistant_name}\" Not Available."