예제 #1
0
                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)
예제 #2
0
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
예제 #3
0
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."