Stage 07.3.1 - auto trading background runner and live screen
This commit is contained in:
@@ -3,12 +3,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from aiogram import F, Router
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
|
||||
from src.telegram.ui.common import mode_line
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
from src.trading.auto.service import AutoTradeService
|
||||
|
||||
|
||||
@@ -49,12 +50,9 @@ def _signal_label(signal: str | None) -> str:
|
||||
def _auto_keyboard() -> InlineKeyboardMarkup:
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
# 1 ряд
|
||||
builder.button(text="▶️ Start", callback_data="auto:start")
|
||||
builder.button(text="👀 Watch", callback_data="auto:observe")
|
||||
builder.button(text="🛑 Stop", callback_data="auto:stop")
|
||||
|
||||
# 2 ряд
|
||||
builder.button(text="🛠️ Настройки", callback_data="settings:auto")
|
||||
|
||||
builder.adjust(3, 1)
|
||||
@@ -64,10 +62,6 @@ def _auto_keyboard() -> InlineKeyboardMarkup:
|
||||
# собрать текст экрана
|
||||
def _build_auto_text() -> str:
|
||||
service = AutoTradeService()
|
||||
|
||||
# выполнить один цикл анализа
|
||||
service.run_cycle()
|
||||
|
||||
state = service.get_state()
|
||||
|
||||
strategy = _strategy_label(state.strategy)
|
||||
@@ -86,7 +80,7 @@ def _build_auto_text() -> str:
|
||||
)
|
||||
|
||||
|
||||
# отрисовать экран
|
||||
# отрисовать live-экран автоторговли
|
||||
async def _render_auto_screen(
|
||||
target_message: Message,
|
||||
*,
|
||||
@@ -98,21 +92,47 @@ async def _render_auto_screen(
|
||||
try:
|
||||
await target_message.edit_text(text, reply_markup=_auto_keyboard())
|
||||
except TelegramBadRequest as exc:
|
||||
if "message is not modified" in str(exc).lower():
|
||||
return
|
||||
raise
|
||||
else:
|
||||
await target_message.answer(text, reply_markup=_auto_keyboard())
|
||||
if "message is not modified" not in str(exc).lower():
|
||||
raise
|
||||
|
||||
AutoTradeRunner.register_screen(
|
||||
bot=target_message.bot,
|
||||
chat_id=target_message.chat.id,
|
||||
message_id=target_message.message_id,
|
||||
render_text=_build_auto_text,
|
||||
render_markup=_auto_keyboard,
|
||||
)
|
||||
return
|
||||
|
||||
sent_message = await target_message.answer(text, reply_markup=_auto_keyboard())
|
||||
|
||||
AutoTradeRunner.register_screen(
|
||||
bot=sent_message.bot,
|
||||
chat_id=sent_message.chat.id,
|
||||
message_id=sent_message.message_id,
|
||||
render_text=_build_auto_text,
|
||||
render_markup=_auto_keyboard,
|
||||
)
|
||||
|
||||
|
||||
# открыть экран из меню
|
||||
# открыть экран из главного меню
|
||||
@router.message(F.text.in_({"🤖 Автоторговля", "🤖 Авто"}))
|
||||
async def open_auto(message: Message, state: FSMContext) -> None:
|
||||
await state.clear()
|
||||
|
||||
AutoTradeRunner.set_current_screen("auto")
|
||||
|
||||
current_state = AutoTradeService().get_state()
|
||||
if current_state.status in {"RUNNING", "OBSERVING"}:
|
||||
await AutoTradeRunner.delete_registered_screen(
|
||||
bot=message.bot,
|
||||
chat_id=message.chat.id,
|
||||
)
|
||||
|
||||
await _render_auto_screen(message, edit_mode=False)
|
||||
|
||||
|
||||
# открыть экран callback
|
||||
# открыть экран через callback
|
||||
@router.callback_query(F.data == "auto:home")
|
||||
async def open_auto_from_callback(callback: CallbackQuery, state: FSMContext) -> None:
|
||||
await state.clear()
|
||||
@@ -121,6 +141,7 @@ async def open_auto_from_callback(callback: CallbackQuery, state: FSMContext) ->
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
AutoTradeRunner.set_current_screen("auto")
|
||||
await _render_auto_screen(callback.message, edit_mode=True)
|
||||
await callback.answer()
|
||||
|
||||
@@ -131,6 +152,9 @@ async def auto_start(callback: CallbackQuery) -> None:
|
||||
service = AutoTradeService()
|
||||
_, message = service.start()
|
||||
|
||||
AutoTradeRunner.set_current_screen("auto")
|
||||
AutoTradeRunner.start()
|
||||
|
||||
if callback.message is not None:
|
||||
await _render_auto_screen(callback.message, edit_mode=True)
|
||||
|
||||
@@ -143,6 +167,9 @@ async def auto_observe(callback: CallbackQuery) -> None:
|
||||
service = AutoTradeService()
|
||||
_, message = service.observe()
|
||||
|
||||
AutoTradeRunner.set_current_screen("auto")
|
||||
AutoTradeRunner.start()
|
||||
|
||||
if callback.message is not None:
|
||||
await _render_auto_screen(callback.message, edit_mode=True)
|
||||
|
||||
@@ -155,6 +182,8 @@ async def auto_stop(callback: CallbackQuery) -> None:
|
||||
service = AutoTradeService()
|
||||
_, message = service.stop()
|
||||
|
||||
AutoTradeRunner.stop()
|
||||
|
||||
if callback.message is not None:
|
||||
await _render_auto_screen(callback.message, edit_mode=True)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from src.telegram.handlers.journal_ui import (
|
||||
render_actions,
|
||||
)
|
||||
from src.trading.journal.service import JournalService
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
|
||||
|
||||
router = Router(name="journal")
|
||||
@@ -45,6 +46,7 @@ async def _show_journal_page(
|
||||
page: int,
|
||||
edit_mode: bool,
|
||||
) -> None:
|
||||
AutoTradeRunner.set_current_screen("journal")
|
||||
service = JournalService()
|
||||
|
||||
total = service.get_total_count()
|
||||
@@ -64,6 +66,7 @@ async def _show_journal_page(
|
||||
|
||||
@router.callback_query(F.data == "journal:actions")
|
||||
async def journal_actions(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("journal")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
@@ -178,6 +181,7 @@ async def export_journal_xlsx(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "journal:clear_confirm")
|
||||
async def clear_journal_confirm(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("journal")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
@@ -16,6 +16,7 @@ from src.telegram.ui.exchange_error import (
|
||||
show_message_exchange_error,
|
||||
)
|
||||
from src.trading.journal.service import JournalService
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
|
||||
|
||||
router = Router(name="market")
|
||||
@@ -72,6 +73,8 @@ async def _render_market_screen(
|
||||
edit_mode: bool,
|
||||
action: str,
|
||||
) -> None:
|
||||
AutoTradeRunner.set_current_screen("market")
|
||||
|
||||
service = ExchangeService()
|
||||
journal = JournalService()
|
||||
requested_symbol = service.settings.default_symbol
|
||||
|
||||
@@ -25,6 +25,7 @@ from src.telegram.ui.exchange_error import (
|
||||
)
|
||||
from src.trading.accounts.service import AccountsService
|
||||
from src.trading.journal.service import JournalService
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
|
||||
|
||||
router = Router(name="portfolio")
|
||||
@@ -70,6 +71,8 @@ async def _render_portfolio_screen(
|
||||
edit_mode: bool,
|
||||
action: str,
|
||||
) -> None:
|
||||
AutoTradeRunner.set_current_screen("portfolio")
|
||||
|
||||
service = AccountsService()
|
||||
exchange_service = ExchangeService()
|
||||
journal = JournalService()
|
||||
|
||||
@@ -12,6 +12,7 @@ from src.core.config import load_settings
|
||||
from src.core.constants import APP_NAME, APP_VERSION
|
||||
from src.trading.journal.service import JournalService
|
||||
from src.trading.auto.service import AutoTradeService
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
|
||||
|
||||
router = Router(name="system")
|
||||
@@ -44,6 +45,8 @@ async def _render_system_screen(
|
||||
chat_id: int | None,
|
||||
action: str,
|
||||
) -> None:
|
||||
AutoTradeRunner.set_current_screen("system")
|
||||
|
||||
journal = JournalService()
|
||||
|
||||
journal.log_ui_info(
|
||||
@@ -166,6 +169,7 @@ async def open_system_management(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "settings:auto")
|
||||
async def open_auto_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
@@ -203,6 +207,7 @@ async def open_auto_settings(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "settings:auto_strategy")
|
||||
async def open_auto_strategy_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
@@ -232,11 +237,13 @@ async def set_auto_strategy(callback: CallbackQuery) -> None:
|
||||
if callback.message is not None:
|
||||
await open_auto_settings(callback)
|
||||
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
await callback.answer("Стратегия обновлена")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:auto_symbol")
|
||||
async def open_auto_symbol_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
@@ -268,11 +275,13 @@ async def set_auto_symbol(callback: CallbackQuery) -> None:
|
||||
if callback.message is not None:
|
||||
await open_auto_settings(callback)
|
||||
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
await callback.answer("Инструмент обновлён")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:auto_risk")
|
||||
async def open_auto_risk_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
@@ -302,6 +311,7 @@ async def set_auto_risk(callback: CallbackQuery) -> None:
|
||||
if callback.message is not None:
|
||||
await open_auto_settings(callback)
|
||||
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
await callback.answer("Риск обновлён")
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from src.telegram.handlers.trade.new_order import (
|
||||
show_recent_drafts,
|
||||
start_new_order_draft,
|
||||
)
|
||||
from src.trading.auto.runner import AutoTradeRunner
|
||||
|
||||
router = Router(name="trade_main")
|
||||
|
||||
@@ -96,6 +97,8 @@ def _trade_settings_text() -> str:
|
||||
|
||||
@router.message(F.text.in_({"📊 Торговля", "⚡ Торговля", "Торговля"}))
|
||||
async def open_trade(message: Message) -> None:
|
||||
AutoTradeRunner.set_current_screen("trade")
|
||||
|
||||
await message.answer(
|
||||
_trade_home_text(),
|
||||
reply_markup=_trade_home_keyboard(),
|
||||
@@ -107,6 +110,8 @@ async def open_trade_home_callback(
|
||||
callback: CallbackQuery,
|
||||
state: FSMContext,
|
||||
) -> None:
|
||||
AutoTradeRunner.set_current_screen("trade")
|
||||
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
|
||||
@@ -137,6 +142,8 @@ async def open_new_order_from_trade(
|
||||
|
||||
@router.callback_query(F.data == "trade:orders")
|
||||
async def open_orders_from_trade(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("trade")
|
||||
|
||||
await callback.answer()
|
||||
if callback.message is not None:
|
||||
await callback.message.edit_text(
|
||||
@@ -158,6 +165,8 @@ async def open_drafts_from_orders(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "trade:history")
|
||||
async def open_trade_history(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("trade")
|
||||
|
||||
await callback.answer()
|
||||
if callback.message is not None:
|
||||
await callback.message.edit_text(
|
||||
@@ -196,6 +205,8 @@ async def open_canceled_history(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "trade:settings")
|
||||
async def open_trade_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("trade")
|
||||
|
||||
await callback.answer()
|
||||
if callback.message is not None:
|
||||
await callback.message.edit_text(
|
||||
|
||||
Reference in New Issue
Block a user