Path: blob/master/ invest-robot-contest_tinkoffSDK-master/async_telebot_fb.py
5925 views
import asyncio1import logging2import os3from contextlib import suppress45from aiogram import Bot, Dispatcher, executor, types6from aiogram.dispatcher.filters import Text7from aiogram.dispatcher.filters.state import State, StatesGroup8from aiogram.utils.callback_data import CallbackData9from aiogram.utils.exceptions import (BotBlocked, MessageNotModified,10NetworkError)1112import my_moving_average13import robot_fatbold1415BOT_TOKEN = os.environ["INVEST_BOT_TOKEN"]16password = os.environ["INVEST_BOT_PASSWORD"]17available_passwords = [password]181920# Состояния для проверки доступа к боту21class bot_access(StatesGroup):22waiting_for_password = State()23waiting_for_start = State()242526""" Переключатели для понимания в каком состоянии находится торговый робот27if robot_must_work == False, то при следующем выходе из генератора, цикл28прервется и торговый робот будет отключен.29"""30trade_robot_states = {31"status_trade_robot": False,32"robot_must_work": True33}3435bot_access.waiting_for_password.set()3637# Объект бота38bot = Bot(token=BOT_TOKEN)39# Диспетчер для бота40dp = Dispatcher(bot)41# Включаем логирование, чтобы не пропустить важные сообщения42logging.basicConfig(level=logging.INFO)4344help = """45/help - показывает подсказку \n46/set - устанавливает настройки \n47Cообщение "Запустить торгового робота" запускает робота с настройками,48которые ты задал или настройками по умолчанию. \n49Cообщение "Остановить торгового робота" останавливает робота50примерно за 60 сек. \n51Cообщение "Настройки" показывает способ задать настройки \n5253Робот работает по стратегии: \n54short_ma > long_ma открывает позицию \n55short_ma < long_ma продает акции \n565758"""5960# Список доступных параметров61trade_parametrs = (62'long_ma',63'short_ma',64'std_period',65'start_balance_units',66'long_ma_min',67'long_ma_max',68'short_ma_min',69'short_ma_max',70'std_period_min',71'std_period_max',72)737475# Настройки по умолчанию для боевого робота и песочницы76user_data = {77'long_ma': 15,78'short_ma': 3,79'std_period': 5,80'start_balance_units': 100000,81'long_ma_min': 13,82'long_ma_max': 15,83'short_ma_min': 3,84'short_ma_max': 4,85'std_period_min': 6,86'std_period_max': 8,87}888990def check_access() -> bool:91if bot_access.waiting_for_password:92return False939495def get_keyboard_fab(parametr: str) -> types.InlineKeyboardMarkup:96buttons = [97types.InlineKeyboardButton(98text="-1",99callback_data=callback_numbers.new(100parametr=parametr,101action="decr")),102types.InlineKeyboardButton(103text="+1",104callback_data=callback_numbers.new(105parametr=parametr,106action="incr")),107types.InlineKeyboardButton(108text="Подтвердить",109callback_data=callback_numbers.new(110parametr=parametr,111action="finish"))]112keyboard = types.InlineKeyboardMarkup(row_width=2)113keyboard.add(*buttons)114return keyboard115116117async def update_num_text_fab(message: types.Message,118parametr: str, new_value: int):119with suppress(MessageNotModified):120await message.edit_text(f"Укажите значение {parametr}: {new_value}",121reply_markup=get_keyboard_fab(parametr))122123124callback_numbers = CallbackData("numbers", "parametr", "action")125126callback_sets = CallbackData("sets", "parametr")127128129@dp.callback_query_handler(callback_sets.filter())130async def callbacks_change_parametr(call: types.CallbackQuery,131callback_data: dict):132133user_value = user_data[callback_data["parametr"]]134parametr = callback_data["parametr"]135136await update_num_text_fab(call.message, parametr, user_value)137138await call.answer()139140141@dp.callback_query_handler(callback_numbers.filter(action=["incr", "decr"]))142async def callbacks_num_change(call: types.CallbackQuery, callback_data: dict):143144parametr = callback_data["parametr"]145user_value = user_data[parametr]146147action = callback_data["action"]148149if action == "incr":150user_data[parametr] = user_value + 1151await update_num_text_fab(call.message, parametr, user_value + 1)152elif action == "decr":153user_data[parametr] = user_value - 1154await update_num_text_fab(call.message, parametr, user_value - 1)155await call.answer()156157158@dp.callback_query_handler(callback_numbers.filter(action=["finish"]))159async def callbacks_num_finish_fab(call: types.CallbackQuery,160callback_data: dict):161162parametr = callback_data["parametr"]163user_value = user_data[parametr]164await call.message.edit_text(f"""Установлено значение {parametr}:165{user_value}""")166167168@dp.message_handler(commands="start")169async def cmd_start(message: types.Message):170171await message.answer("Введите пароль")172await bot_access.waiting_for_password.set()173174175async def check_password(message):176if message.text not in available_passwords:177await message.answer("Пароль неверный! Укажите правильный пароль:")178return179await bot_access.waiting_for_start.set()180181"""Запускает бота"""182greeting = """Привет! Я робот. Меня зовут Толстый жирный.\n183Я умею торговать на бирже.184И делать твое депо толстым и жирным.\n185Ты можешь ввести команду /help и прочитать инструкцию186по работе со мной.\n Она выглядит так:187"""188await message.answer(greeting)189await message.answer(help)190191keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)192buttons = [193"Запустить торгового робота",194"Тест в песочнице",195"Настройки",196"Инструкция",197"Баланс"198]199keyboard.add(*buttons)200await message.answer("Что делать, хозяин?", reply_markup=keyboard)201202203@dp.message_handler(Text(equals="главное меню"))204async def main_menu(message: types.Message):205keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)206buttons = [207"Запустить торгового робота",208"Тест в песочнице",209"Настройки",210"Инструкция",211"Баланс"212]213keyboard.add(*buttons)214await message.answer("Что делать, хозяин?", reply_markup=keyboard)215216217@dp.message_handler(Text(equals="Баланс"))218async def get_balance(message: types.Message):219220# info = await robot_fatbold.get_balance()221await message.answer("""Пока не работает. Потому, что надо передавать222все параметры стратегии, чтобы получить данные223""")224225226@dp.message_handler(commands=password)227async def cmd_password(message: types.Message):228"""Запускает бота"""229greeting = """Привет! Я робот. Меня зовут Толстый жирный.\n230Я умею торговать на бирже.231И делать твое депо толстым и жирным.\n232Ты можешь ввести команду /help233и прочитать инструкцию по работе со мной.\n234Она выглядит так:235"""236await message.answer(greeting)237await message.answer(help)238239keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)240buttons = [241"Запустить торгового робота",242"Тест в песочнице",243"Настройки",244"Инструкция",245"Баланс"246]247keyboard.add(*buttons)248await message.answer("Что делать, хозяин?", reply_markup=keyboard)249250251@dp.message_handler(Text(equals="Запустить торгового робота"))252async def start_trade(message: types.Message):253254# if check_access() == False:255# await message.answer("У вас нет доступа к боту. Введите пароль:")256# return257258if not trade_robot_states["status_trade_robot"]:259260status = "Working"261262gen = robot_fatbold.main(263long_ma=user_data["long_ma"],264short_ma=user_data["short_ma"],265std_period=user_data["std_period"])266267flag = True # Чтобы один раз сообщить, что робот запущен.268269while status == "Working" and trade_robot_states["robot_must_work"]:270response = await gen.__anext__()271272trade_robot_states["status_trade_robot"] = True273274status = response['status']275276await asyncio.sleep(0.1)277278if flag and status == "Working":279keyboard = types.ReplyKeyboardMarkup(280resize_keyboard=True, row_width=2)281buttons = [282"Остановить торгового робота",283"Тест в песочнице",284"Настройки",285"Инструкция",286"Баланс"287]288keyboard.add(*buttons)289await message.answer("Торговый робот запущен!",290reply_markup=keyboard)291flag = False292trade_robot_states["status_trade_robot"] = True293trade_robot_states["robot_must_work"] = True294295# status = response['status']296# Робот работает ничего не делаем297298trade_robot_states["status_trade_robot"] = False # Изменим статус299# Поднимим флаг, чтобы робот мог запуститься300trade_robot_states["robot_must_work"] = True301balance = response['balance']302profit = response['profit']303shares = response['shares']304send_message = f"""305Робот остановлен.306Текущий cтатус: {status} \n307Сумма на счете: {balance:.2f} \n308Стоимость акций: {shares:.2f} \n309Прибыль с момента запуска: {profit:.2f}310"""311312await message.answer(send_message)313keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)314buttons = [315"Запустить торгового робота",316"Тест в песочнице",317"Настройки",318"Инструкция",319"Баланс"320]321keyboard.add(*buttons)322await message.answer("Что делать, хозяин?", reply_markup=keyboard)323324elif trade_robot_states["status_trade_robot"]:325await message.answer("Робот уже запущен")326else:327await message.answer("Робот в непонятном состоянии")328329330@dp.message_handler(lambda message: message.text ==331"Остановить торгового робота")332async def stop_trade(message: types.Message):333334if trade_robot_states['status_trade_robot']:335# Глобальная переменная для остановки робота336trade_robot_states['robot_must_work'] = False337await message.answer("Робот будет остановлен в течении ~60 сек.")338else:339keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)340buttons = [341"Запустить торгового робота",342"Тест в песочнице",343"Настройки",344"Инструкция",345"Баланс"346]347keyboard.add(*buttons)348349await message.answer("Робот и так не работал", reply_markup=keyboard)350351352@dp.message_handler(lambda message: message.text == "Тест в песочнице")353async def sandbox_test(message: types.Message):354send_message = "Запущен тест на песочнице:"355await message.answer(send_message)356357results = my_moving_average.main(358user_data['start_balance_units'],359user_data['long_ma_min'],360user_data['long_ma_max'],361user_data['short_ma_min'],362user_data['short_ma_max'],363user_data['std_period_min'],364user_data['std_period_max']365)366367send_message = "Тест на песочнице закончен:"368await message.answer(send_message)369370best_settings = results[0]['settings']371best_result_message = f"""372Лучшие настройки:373Прибыль: {float(results[0]['profit']):.2f}374Инструмент: {best_settings['stock']}375long_ma: {best_settings['long_ma']}376short_ma: {best_settings['short_ma']}377std_period: {best_settings['std_period']}378tf: {best_settings['tf']}379period: {best_settings['period']}380"""381382await message.answer(best_result_message)383384send_message = "Остальные результаты:"385await message.answer(send_message)386387for i in range(1, len(results)):388settings = results[i]['settings']389result_message = f"""390Прибыль: {float(results[i]['profit']):.2f}391Инструмент: {settings['stock']}392long_ma: {settings['long_ma']}393short_ma: {settings['short_ma']}394std_period: {settings['std_period']}395tf: {settings['tf']}396period: {settings['period']}397"""398await message.answer(result_message)399400401@dp.message_handler(lambda message: message.text == "Настройки")402async def settings_setup(message: types.Message):403404buttons = []405406for p in trade_parametrs:407# Получим текущее значение параметра для текста на кнопке408user_value = user_data[p]409button_text = p + ":" + str(user_value)410buttons.append(411types.InlineKeyboardButton(412text=button_text,413callback_data=callback_sets.new(414parametr=p)))415416keyboard = types.InlineKeyboardMarkup(row_width=1)417keyboard.add(*buttons)418419await message.answer("Выберите параметр:", reply_markup=keyboard)420421422@dp.message_handler(commands="set")423async def set(message: types.Message):424425global long_ma426global short_ma427global std_period428429m_message = message.text.split(sep=";")430431long_ma = m_message[0].split()[1]432short_ma = m_message[1]433std_period = m_message[2]434435await message.answer(f"""Установлены настройки робота \n436long_ma: {long_ma} \n437short_ma: {short_ma} \n438std_period: {std_period} \n439""")440441442@dp.message_handler(lambda message: message.text == "Инструкция")443async def show_help(message: types.Message):444445await message.answer(help)446447448@dp.errors_handler(exception=BotBlocked)449async def error_bot_blocked(update: types.Update, exception: BotBlocked):450# Update: объект события от Telegram. Exception: объект исключения451# Здесь можно как-то обработать блокировку, например, удалить пользователя452# из БД453print(454f"""Меня заблокировал пользователь!\n455Сообщение: {update}\nОшибка: {exception}456""")457458# Такой хэндлер должен всегда возвращать True,459# если дальнейшая обработка не требуется.460return True461462463@dp.errors_handler(exception=NetworkError)464async def error_Network_Error(update: types.Update, exception: NetworkError):465# Update: объект события от Telegram. Exception: объект исключения466# Здесь можно как-то обработать блокировку, например, удалить пользователя467# из БД468print(469f"""ClientConnectorError: Cannot connect to host470api.telegram.org:443 ssl:default [None] \n471Сообщение: {update}\nОшибка: {exception}472""")473474# Такой хэндлер должен всегда возвращать True,475# если дальнейшая обработка не требуется.476return True477478479def register_handlers_access(dp: Dispatcher):480dp.register_message_handler(cmd_start, commands="start", state="*")481dp.register_message_handler(482check_password,483state=bot_access.waiting_for_password)484dp.register_message_handler(main_menu, state=bot_access.waiting_for_start)485486487if __name__ == "__main__":488# Запуск бота489executor.start_polling(dp, skip_updates=True)490491492