Stage 07.4.3.1 — trend strategy stabilization
This commit is contained in:
@@ -46,6 +46,101 @@ def _signal_label(signal: str | None) -> str:
|
||||
return mapping.get(signal or "", "—")
|
||||
|
||||
|
||||
# красивое отображение решения
|
||||
def _decision_label(status: str) -> str:
|
||||
mapping = {
|
||||
"WAITING": "🟡 Ожидание",
|
||||
"CONFIRMING": "🟠 Подтверждение",
|
||||
"READY": "🟢 Готово к входу",
|
||||
"BLOCKED": "🔴 Заблокировано",
|
||||
}
|
||||
return mapping.get(status, status)
|
||||
|
||||
|
||||
# компактное значение или заглушка
|
||||
def _value_or_dash(value: object) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return str(value)
|
||||
|
||||
|
||||
# формат цены
|
||||
def _price_or_dash(value: float | None) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return f"{value:.2f}"
|
||||
|
||||
|
||||
# формат USD
|
||||
def _usd_or_dash(value: float | None) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return f"{value:.2f} USD"
|
||||
|
||||
|
||||
# формат размера позиции
|
||||
def _size_or_dash(value: float | None) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return f"{value:.8f}".rstrip("0").rstrip(".")
|
||||
|
||||
|
||||
# формат плеча
|
||||
def _leverage_or_dash(value: float | None) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return f"{value:.1f}x"
|
||||
|
||||
|
||||
# формат торгового инструмента для UI
|
||||
def _format_symbol(symbol: str | None) -> str:
|
||||
if not symbol:
|
||||
return "—"
|
||||
|
||||
base_symbol = symbol.split("_", 1)[0]
|
||||
parts = base_symbol.split("/", 1)
|
||||
|
||||
if len(parts) == 2:
|
||||
return f"{parts[0]} / {parts[1]}"
|
||||
|
||||
return base_symbol
|
||||
|
||||
|
||||
# стратегия для компактного UI
|
||||
def _compact_strategy(strategy: str | None) -> str:
|
||||
if not strategy:
|
||||
return "—"
|
||||
return strategy.upper()
|
||||
|
||||
|
||||
# плечо для компактного UI
|
||||
def _compact_leverage(value: float | None) -> str:
|
||||
if value is None:
|
||||
return "—"
|
||||
return f"x{value:g}"
|
||||
|
||||
|
||||
# проверка, настроена ли автоторговля минимально
|
||||
def _is_auto_configured(state) -> bool:
|
||||
return bool(
|
||||
state.symbol
|
||||
and state.strategy
|
||||
and state.risk_percent is not None
|
||||
)
|
||||
|
||||
|
||||
# строка инструмента / стратегии / плеча
|
||||
def _context_line(state) -> str:
|
||||
symbol = _format_symbol(state.symbol)
|
||||
strategy = _compact_strategy(state.strategy)
|
||||
leverage = _compact_leverage(state.leverage)
|
||||
|
||||
if leverage == "—":
|
||||
return f"{symbol} · {strategy}"
|
||||
|
||||
return f"{symbol} · {strategy} · {leverage}"
|
||||
|
||||
|
||||
# клавиатура автоторговли
|
||||
def _auto_keyboard() -> InlineKeyboardMarkup:
|
||||
builder = InlineKeyboardBuilder()
|
||||
@@ -64,21 +159,46 @@ def _build_auto_text() -> str:
|
||||
service = AutoTradeService()
|
||||
state = service.get_state()
|
||||
|
||||
strategy = _strategy_label(state.strategy)
|
||||
account_mode = "DEMO" if "DEMO" in mode_line().upper() else "LIVE"
|
||||
risk = f"{state.risk_percent:.1f}%" if state.risk_percent is not None else "—"
|
||||
configured = _is_auto_configured(state)
|
||||
|
||||
header = (
|
||||
"<b>🤖 Автоторговля</b>\n"
|
||||
f"🔸 {account_mode} аккаунт\n\n"
|
||||
)
|
||||
|
||||
if state.status == "OFF":
|
||||
if not configured:
|
||||
return (
|
||||
f"{header}"
|
||||
"⚪ Выключена\n\n"
|
||||
"⚠️ Не настроена\n"
|
||||
"Настрой параметры"
|
||||
)
|
||||
|
||||
return (
|
||||
f"{header}"
|
||||
"⚪ Выключена\n\n"
|
||||
f"{_context_line(state)}\n"
|
||||
f"Risk: {risk}"
|
||||
)
|
||||
|
||||
status_line = (
|
||||
"🟢 Активна"
|
||||
if state.status == "RUNNING"
|
||||
else "👀 Наблюдение"
|
||||
)
|
||||
|
||||
return (
|
||||
"<b>🤖 Автоторговля</b>\n"
|
||||
f"{mode_line()}"
|
||||
f"Статус: {_status_label(state.status)}\n"
|
||||
f"Стратегия: {strategy}\n"
|
||||
f"Инструмент: {state.symbol}\n"
|
||||
f"Риск: {risk}\n"
|
||||
f"PnL: {state.pnl_usd:.2f} USD\n"
|
||||
f"Последний анализ: {state.last_check_at or '—'}\n"
|
||||
f"Сигнал: {_signal_label(state.last_signal)} · {state.last_signal_repeat_count} подряд\n"
|
||||
f"Уверенность: {state.last_signal_confidence:.2f}\n"
|
||||
f"Причина: {state.last_signal_reason or '—'}"
|
||||
f"{header}"
|
||||
f"{status_line}\n\n"
|
||||
f"{_context_line(state)}\n\n"
|
||||
f"{_signal_label(state.last_signal)} ×{state.last_signal_repeat_count} "
|
||||
f"· {state.decision_status}\n\n"
|
||||
f"Pos: {_value_or_dash(state.position_side)} | "
|
||||
f"PnL: {_usd_or_dash(state.unrealized_pnl_usd)}\n"
|
||||
f"Risk: {risk}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -168,10 +168,16 @@ 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
|
||||
|
||||
AutoTradeRunner.unregister_screen(
|
||||
chat_id=callback.message.chat.id,
|
||||
message_id=callback.message.message_id,
|
||||
)
|
||||
|
||||
state = AutoTradeService().get_state()
|
||||
|
||||
strategy_map = {
|
||||
@@ -181,13 +187,15 @@ async def open_auto_settings(callback: CallbackQuery) -> None:
|
||||
}
|
||||
strategy = strategy_map.get(state.strategy or "", "—")
|
||||
risk = f"{state.risk_percent:.1f}%" if state.risk_percent is not None else "—"
|
||||
leverage = f"x{state.leverage:g}" if state.leverage is not None else "—"
|
||||
|
||||
text = (
|
||||
"<b>🤖 Автоторговля</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки\n\n"
|
||||
f"Стратегия: {strategy}\n"
|
||||
f"Инструмент: {state.symbol}\n"
|
||||
f"Риск: {risk}\n\n"
|
||||
f"Риск: {risk}\n"
|
||||
f"Плечо: {leverage}\n\n"
|
||||
"Выберите настройку:"
|
||||
)
|
||||
|
||||
@@ -195,9 +203,10 @@ async def open_auto_settings(callback: CallbackQuery) -> None:
|
||||
builder.button(text="🧠 Стратегия", callback_data="settings:auto_strategy")
|
||||
builder.button(text="📈 Инструмент", callback_data="settings:auto_symbol")
|
||||
builder.button(text="🛡️ Риск", callback_data="settings:auto_risk")
|
||||
builder.button(text="⚙️ Плечо", callback_data="settings:auto_leverage")
|
||||
builder.button(text="⬅️ Назад", callback_data="system:management")
|
||||
builder.button(text="🤖 Автоторговля", callback_data="auto:home")
|
||||
builder.adjust(2, 1, 2)
|
||||
builder.adjust(2, 2, 2)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
@@ -313,6 +322,46 @@ async def set_auto_risk(callback: CallbackQuery) -> None:
|
||||
await callback.answer("Риск обновлён")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:auto_leverage")
|
||||
async def open_auto_leverage_settings(callback: CallbackQuery) -> None:
|
||||
AutoTradeRunner.set_current_screen("settings_auto")
|
||||
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>⚙️ Плечо</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки · Автоторговля\n\n"
|
||||
"Выберите плечо:"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="x1", callback_data="settings:auto_leverage:1")
|
||||
builder.button(text="x2", callback_data="settings:auto_leverage:2")
|
||||
builder.button(text="x3", callback_data="settings:auto_leverage:3")
|
||||
builder.button(text="x5", callback_data="settings:auto_leverage:5")
|
||||
builder.button(text="x10", callback_data="settings:auto_leverage:10")
|
||||
builder.button(text="x20", callback_data="settings:auto_leverage:20")
|
||||
builder.button(text="⬅️ Назад", callback_data="settings:auto")
|
||||
builder.adjust(3, 3, 1)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("settings:auto_leverage:"))
|
||||
async def set_auto_leverage(callback: CallbackQuery) -> None:
|
||||
leverage = float(callback.data.split(":", 2)[2])
|
||||
AutoTradeService().set_leverage(leverage)
|
||||
|
||||
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:trade")
|
||||
async def open_trade_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
|
||||
Reference in New Issue
Block a user