07.4.4.1.4 Entry Decision Diagnostics Layer
This commit is contained in:
@@ -31,6 +31,9 @@ EVENT_TITLES = {
|
|||||||
"market_stream_disconnected": "Рынок",
|
"market_stream_disconnected": "Рынок",
|
||||||
"market_symbol_changed": "Рынок",
|
"market_symbol_changed": "Рынок",
|
||||||
|
|
||||||
|
# Мониторинг позиций
|
||||||
|
"entry_blocked": "Вход в позицию",
|
||||||
|
|
||||||
# Журнал
|
# Журнал
|
||||||
"journal_exported": "Журнал",
|
"journal_exported": "Журнал",
|
||||||
"journal_export_error": "Журнал",
|
"journal_export_error": "Журнал",
|
||||||
|
|||||||
@@ -155,16 +155,23 @@ def _build_waiting_text(state) -> str:
|
|||||||
entry_price_override=price,
|
entry_price_override=price,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
signal_lines = [
|
||||||
|
_signal_line(state),
|
||||||
|
_market_state_line(state),
|
||||||
|
_entry_block_line(state),
|
||||||
|
*_signal_confidence_lines(state),
|
||||||
|
*_execution_block_lines(state),
|
||||||
|
]
|
||||||
|
|
||||||
|
signal_lines = [line for line in signal_lines if line]
|
||||||
|
|
||||||
parts = [
|
parts = [
|
||||||
f"🤖 Автоторговля {_status_text(state.status)}",
|
f"🤖 Автоторговля {_status_text(state.status)}",
|
||||||
_account_mode_line(),
|
_account_mode_line(),
|
||||||
"",
|
"",
|
||||||
f"<b>Доступно</b> · $ {_format_money_compact(available)}",
|
f"<b>Доступно</b> · $ {_format_money_compact(available)}",
|
||||||
"",
|
"",
|
||||||
_signal_line(state),
|
*signal_lines,
|
||||||
_market_state_line(state),
|
|
||||||
*_signal_confidence_lines(state),
|
|
||||||
*_execution_block_lines(state),
|
|
||||||
"",
|
"",
|
||||||
"🧾 <b>Подготовка ордера</b>",
|
"🧾 <b>Подготовка ордера</b>",
|
||||||
"",
|
"",
|
||||||
@@ -253,16 +260,28 @@ def _market_state_line(state) -> str:
|
|||||||
return labels.get(market_state, "⏳ Рынок · Идёт анализ")
|
return labels.get(market_state, "⏳ Рынок · Идёт анализ")
|
||||||
|
|
||||||
|
|
||||||
|
def _entry_block_line(state) -> str:
|
||||||
|
message = getattr(state, "entry_block_message", None)
|
||||||
|
|
||||||
|
if not message:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return f"Вход в позицию · {message}"
|
||||||
|
|
||||||
|
|
||||||
def _execution_block_lines(state) -> list[str]:
|
def _execution_block_lines(state) -> list[str]:
|
||||||
lines: list[str] = []
|
lines: list[str] = []
|
||||||
|
|
||||||
reason = getattr(state, "execution_block_reason", None)
|
reason = getattr(state, "execution_block_reason", None)
|
||||||
if reason:
|
if reason:
|
||||||
lines.append(f"Blocked · {reason}")
|
lines.append(f"Исполнение · {reason}")
|
||||||
|
|
||||||
adjustment = getattr(state, "execution_size_adjustment_reason", None)
|
adjustment = getattr(state, "execution_size_adjustment_reason", None)
|
||||||
|
|
||||||
if adjustment == "MARGIN_LIMIT":
|
if adjustment == "MARGIN_LIMIT":
|
||||||
lines.append("Size adjusted by Max Reserved")
|
lines.append(
|
||||||
|
"Позиция ограничена настройкой Max Reserved."
|
||||||
|
)
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class AutoTradeService:
|
|||||||
_last_logged_market_state: str | None = None
|
_last_logged_market_state: str | None = None
|
||||||
_last_logged_market_trend: str | None = None
|
_last_logged_market_trend: str | None = None
|
||||||
_last_logged_market_volatility: str | None = None
|
_last_logged_market_volatility: str | None = None
|
||||||
|
_last_logged_entry_block_reason: str | None = None
|
||||||
_same_signal_count = 0
|
_same_signal_count = 0
|
||||||
|
|
||||||
# debug: принудительно выставить сигнал и decision
|
# debug: принудительно выставить сигнал и decision
|
||||||
@@ -663,6 +664,8 @@ class AutoTradeService:
|
|||||||
state.market_volatility = payload.get("market_volatility")
|
state.market_volatility = payload.get("market_volatility")
|
||||||
state.market_analysis_interval = payload.get("market_analysis_interval")
|
state.market_analysis_interval = payload.get("market_analysis_interval")
|
||||||
state.market_analysis_reason = payload.get("market_analysis_reason")
|
state.market_analysis_reason = payload.get("market_analysis_reason")
|
||||||
|
state.entry_block_reason = payload.get("entry_block_reason")
|
||||||
|
state.entry_block_message = payload.get("entry_block_message")
|
||||||
|
|
||||||
self._log_market_state_if_changed(
|
self._log_market_state_if_changed(
|
||||||
state=state,
|
state=state,
|
||||||
@@ -672,6 +675,48 @@ class AutoTradeService:
|
|||||||
previous_market_volatility=previous_market_volatility,
|
previous_market_volatility=previous_market_volatility,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._log_entry_block_if_changed(
|
||||||
|
state=state,
|
||||||
|
payload=payload,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _log_entry_block_if_changed(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
state: AutoTradeState,
|
||||||
|
payload: dict,
|
||||||
|
) -> None:
|
||||||
|
reason = state.entry_block_reason
|
||||||
|
message = state.entry_block_message
|
||||||
|
|
||||||
|
if not reason or not message:
|
||||||
|
return
|
||||||
|
|
||||||
|
key = f"{state.status}:{state.symbol}:{state.strategy}:{reason}:{message}"
|
||||||
|
|
||||||
|
if key == type(self)._last_logged_entry_block_reason:
|
||||||
|
return
|
||||||
|
|
||||||
|
type(self)._last_logged_entry_block_reason = key
|
||||||
|
|
||||||
|
try:
|
||||||
|
JournalService().log_ui_info(
|
||||||
|
event_type="entry_blocked",
|
||||||
|
message=f"Вход в позицию не выполнен: {message}.",
|
||||||
|
screen="auto",
|
||||||
|
action="entry_diagnostics",
|
||||||
|
payload={
|
||||||
|
**payload,
|
||||||
|
"entry_block_reason": reason,
|
||||||
|
"entry_block_message": message,
|
||||||
|
"symbol": state.symbol,
|
||||||
|
"strategy": state.strategy,
|
||||||
|
"status": state.status,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def _log_market_state_if_changed(
|
def _log_market_state_if_changed(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|||||||
@@ -119,4 +119,10 @@ class AutoTradeState:
|
|||||||
market_analysis_interval: str | None = None
|
market_analysis_interval: str | None = None
|
||||||
|
|
||||||
# объяснение последнего анализа рынка
|
# объяснение последнего анализа рынка
|
||||||
market_analysis_reason: str | None = None
|
market_analysis_reason: str | None = None
|
||||||
|
|
||||||
|
# код причины, почему вход в позицию сейчас не выполнен
|
||||||
|
entry_block_reason: str | None = None
|
||||||
|
|
||||||
|
# человекочитаемое объяснение причины не входа
|
||||||
|
entry_block_message: str | None = None
|
||||||
@@ -92,6 +92,8 @@ class TrendStrategy:
|
|||||||
payload={
|
payload={
|
||||||
**base_payload,
|
**base_payload,
|
||||||
"market_filter_blocked": True,
|
"market_filter_blocked": True,
|
||||||
|
"entry_block_reason": "MARKET_FILTER_BLOCKED",
|
||||||
|
"entry_block_message": "рынок сейчас не подходит для входа",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -451,6 +451,22 @@
|
|||||||
- CSV / XLSX export очищен от эмодзи
|
- CSV / XLSX export очищен от эмодзи
|
||||||
- журнал подготовлен к централизованному event_titles.py и future filters/search layer
|
- журнал подготовлен к централизованному event_titles.py и future filters/search layer
|
||||||
|
|
||||||
|
#### 07.4.4.1.4 ✅ Entry Decision Diagnostics Layer
|
||||||
|
- добавлен диагностический слой причин не входа в позицию
|
||||||
|
- AutoTradeState расширен entry_block_reason и entry_block_message
|
||||||
|
- TrendStrategy начала передавать причины HOLD в payload
|
||||||
|
- добавлены entry_block_reason к market filter / live data / weak impulse сценариям
|
||||||
|
- AutoTradeService синхронизирует entry diagnostics в runtime state
|
||||||
|
- добавлено событие entry_blocked для журнала
|
||||||
|
- журнал пишет причины не входа только при изменении причины
|
||||||
|
- добавлена защита от spam logging одинаковых HOLD-причин
|
||||||
|
- Auto UI показывает строку Вход в позицию · причина
|
||||||
|
- strategy diagnostics отделены от execution diagnostics
|
||||||
|
- execution UI приведён к human-readable стилю
|
||||||
|
- добавлен EVENT_TITLES mapping для entry_blocked
|
||||||
|
- подготовлена база для анализа частоты причин отказа от входа
|
||||||
|
- подготовлена база для adaptive thresholds и настройки чувствительности стратегии
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 07.4.5
|
### 07.4.5
|
||||||
|
|||||||
@@ -427,6 +427,22 @@
|
|||||||
- CSV / XLSX export очищен от эмодзи
|
- CSV / XLSX export очищен от эмодзи
|
||||||
- журнал подготовлен к централизованному event_titles.py и future filters/search layer
|
- журнал подготовлен к централизованному event_titles.py и future filters/search layer
|
||||||
|
|
||||||
|
#### 07.4.4.1.4 ✅ Entry Decision Diagnostics Layer
|
||||||
|
- добавлен диагностический слой причин не входа в позицию
|
||||||
|
- AutoTradeState расширен entry_block_reason и entry_block_message
|
||||||
|
- TrendStrategy начала передавать причины HOLD в payload
|
||||||
|
- добавлены entry_block_reason к market filter / live data / weak impulse сценариям
|
||||||
|
- AutoTradeService синхронизирует entry diagnostics в runtime state
|
||||||
|
- добавлено событие entry_blocked для журнала
|
||||||
|
- журнал пишет причины не входа только при изменении причины
|
||||||
|
- добавлена защита от spam logging одинаковых HOLD-причин
|
||||||
|
- Auto UI показывает строку Вход в позицию · причина
|
||||||
|
- strategy diagnostics отделены от execution diagnostics
|
||||||
|
- execution UI приведён к human-readable стилю
|
||||||
|
- добавлен EVENT_TITLES mapping для entry_blocked
|
||||||
|
- подготовлена база для анализа частоты причин отказа от входа
|
||||||
|
- подготовлена база для adaptive thresholds и настройки чувствительности стратегии
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 07.4.5
|
### 07.4.5
|
||||||
|
|||||||
342
docs/stages/stage-07_4_4_1_4-entry_decision_diagnostics_layer.md
Normal file
342
docs/stages/stage-07_4_4_1_4-entry_decision_diagnostics_layer.md
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
# 07.4.4.1.4 — Entry Decision Diagnostics Layer
|
||||||
|
|
||||||
|
## Цель этапа
|
||||||
|
|
||||||
|
Добавить диагностический слой, который объясняет, почему автоторговля не входит в позицию, даже если рынок движется.
|
||||||
|
|
||||||
|
До этого этапа пользователь видел в интерфейсе в основном `HOLD`, но не всегда понимал причину:
|
||||||
|
|
||||||
|
- рынок не подходит для входа
|
||||||
|
- live-импульс слишком слабый
|
||||||
|
- недостаточно live-данных
|
||||||
|
- сигнал ещё не подтверждён
|
||||||
|
- execution не готов открыть позицию
|
||||||
|
- размер позиции ограничен настройками защиты
|
||||||
|
|
||||||
|
Этап сделал поведение автоторговли более прозрачным и подготовил систему к дальнейшей настройке стратегии.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Что было реализовано
|
||||||
|
|
||||||
|
## 1. Добавлен Entry Decision Diagnostics Layer
|
||||||
|
|
||||||
|
В систему добавлен отдельный слой диагностики входа в позицию.
|
||||||
|
|
||||||
|
Теперь стратегия не просто возвращает `HOLD`, а дополнительно передаёт причину, почему вход не выполнен.
|
||||||
|
|
||||||
|
Это важно, потому что `HOLD` может означать разные ситуации:
|
||||||
|
|
||||||
|
- безопасное ожидание
|
||||||
|
- рынок без выраженного направления
|
||||||
|
- слабый импульс
|
||||||
|
- недостаточно live-данных
|
||||||
|
- неподходящая волатильность
|
||||||
|
- техническая ошибка получения рыночных данных
|
||||||
|
|
||||||
|
После этапа эти причины стали видимыми в runtime state, UI и журнале.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 2. Добавлены поля диагностики входа в AutoTradeState
|
||||||
|
|
||||||
|
В `AutoTradeState` добавлены новые поля:
|
||||||
|
|
||||||
|
- `entry_block_reason`
|
||||||
|
- `entry_block_message`
|
||||||
|
|
||||||
|
`entry_block_reason` хранит технический код причины.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
- `MARKET_FILTER_BLOCKED`
|
||||||
|
- `LIVE_DATA_WAITING`
|
||||||
|
- `WEAK_UP_IMPULSE`
|
||||||
|
- `WEAK_DOWN_IMPULSE`
|
||||||
|
- `INVALID_PRICE`
|
||||||
|
- `SNAPSHOT_ERROR`
|
||||||
|
|
||||||
|
`entry_block_message` хранит человекочитаемое объяснение.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
- «рынок сейчас не подходит для входа»
|
||||||
|
- «недостаточно live-данных для подтверждения»
|
||||||
|
- «слабый импульс вверх»
|
||||||
|
- «слабый импульс вниз»
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 3. TrendStrategy начала отдавать причины отказа от входа
|
||||||
|
|
||||||
|
В `TrendStrategy` причины HOLD были расширены диагностическими payload-полями.
|
||||||
|
|
||||||
|
Теперь, когда стратегия не даёт BUY или SELL, она передаёт:
|
||||||
|
|
||||||
|
- почему вход не разрешён
|
||||||
|
- какой market state был в момент решения
|
||||||
|
- какой live-импульс был рассчитан
|
||||||
|
- сколько live-цен накоплено
|
||||||
|
- какой threshold не был пройден
|
||||||
|
- какой direction ratio был получен
|
||||||
|
|
||||||
|
Это особенно важно для анализа ситуаций, когда визуально рынок движется, но бот всё равно не входит в позицию.
|
||||||
|
|
||||||
|
Например, рынок может расти последние несколько свечей, но стратегия всё ещё может не входить, если:
|
||||||
|
|
||||||
|
- общий market state не подтверждает тренд
|
||||||
|
- live-импульс ниже порога
|
||||||
|
- движение недостаточно устойчивое
|
||||||
|
- подтверждение сигнала ещё не накоплено
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 4. AutoTradeService синхронизирует entry diagnostics
|
||||||
|
|
||||||
|
`AutoTradeService` теперь забирает `entry_block_reason` и `entry_block_message` из payload стратегии и сохраняет их в текущем состоянии автоторговли.
|
||||||
|
|
||||||
|
Это позволило использовать одну и ту же диагностику сразу в нескольких местах:
|
||||||
|
|
||||||
|
- Auto UI
|
||||||
|
- журнал
|
||||||
|
- future analytics layer
|
||||||
|
- future filters/search layer
|
||||||
|
- future AI explanation layer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 5. Добавлено журналирование причин не входа
|
||||||
|
|
||||||
|
Добавлено событие:
|
||||||
|
|
||||||
|
- `entry_blocked`
|
||||||
|
|
||||||
|
Журнал теперь фиксирует не только готовые сигналы и открытие позиций, но и важные причины, почему позиция не была открыта.
|
||||||
|
|
||||||
|
Формат сообщения:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[DEMO] Вход в позицию не выполнен: слабый импульс вверх.
|
||||||
|
```
|
||||||
|
|
||||||
|
или:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[DEMO] Вход в позицию не выполнен: рынок сейчас не подходит для входа.
|
||||||
|
```
|
||||||
|
|
||||||
|
Это позволяет оставить автоторговлю работать долго и потом понять, почему за период не было сделок.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6. Добавлена защита от spam logging
|
||||||
|
|
||||||
|
Причины не входа не пишутся в журнал на каждом цикле.
|
||||||
|
|
||||||
|
Система пишет событие только тогда, когда причина изменилась.
|
||||||
|
|
||||||
|
Например, если бот 30 минут подряд не входит из-за слабого импульса, журнал не будет получать одинаковые записи каждые 5 секунд.
|
||||||
|
|
||||||
|
Если причина изменилась, например:
|
||||||
|
|
||||||
|
- было: слабый импульс вверх
|
||||||
|
- стало: рынок без выраженного направления
|
||||||
|
|
||||||
|
тогда будет записано новое событие.
|
||||||
|
|
||||||
|
Это сохраняет журнал полезным и не превращает его в поток повторяющихся HOLD-сообщений.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 7. Auto UI начал показывать причину не входа
|
||||||
|
|
||||||
|
На экране автоторговли добавлена строка диагностики:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Вход в позицию · слабый импульс вверх
|
||||||
|
```
|
||||||
|
|
||||||
|
или:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Вход в позицию · рынок сейчас не подходит для входа
|
||||||
|
```
|
||||||
|
|
||||||
|
Теперь пользователь видит не просто `HOLD`, а понимает, почему бот ждёт.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 8. Strategy diagnostics отделены от execution diagnostics
|
||||||
|
|
||||||
|
В UI теперь логически разделены два разных типа причин.
|
||||||
|
|
||||||
|
## Entry diagnostics
|
||||||
|
|
||||||
|
Отвечает на вопрос:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Почему стратегия не хочет входить в позицию?
|
||||||
|
```
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
- рынок не подходит
|
||||||
|
- слабый импульс
|
||||||
|
- недостаточно данных
|
||||||
|
|
||||||
|
## Execution diagnostics
|
||||||
|
|
||||||
|
Отвечает на вопрос:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Почему позиция не может быть технически открыта?
|
||||||
|
```
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
- ограничение Max Reserved
|
||||||
|
- execution block
|
||||||
|
- невозможность рассчитать размер позиции
|
||||||
|
|
||||||
|
Это разделение важно, потому что раньше разные причины могли восприниматься как одна проблема.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 9. UI-тексты приведены к единому human-readable стилю
|
||||||
|
|
||||||
|
Устаревшие технические строки были приведены к более понятному виду.
|
||||||
|
|
||||||
|
Например:
|
||||||
|
|
||||||
|
- `Blocked · ...` заменено на `Исполнение · ...`
|
||||||
|
- `Size adjusted by Max Reserved` заменено на `Позиция ограничена настройкой Max Reserved.`
|
||||||
|
- `Вход не выполнен` уточнено до `Вход в позицию не выполнен`
|
||||||
|
|
||||||
|
Это делает интерфейс понятнее для пользователя, который не обязан знать внутреннюю архитектуру execution layer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 10. Добавлен event title для entry diagnostics
|
||||||
|
|
||||||
|
В общий mapping заголовков событий добавлен event title:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"entry_blocked": "Вход"
|
||||||
|
```
|
||||||
|
|
||||||
|
Так журнал сохраняет короткую структуру:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Вход | [DEMO] Вход в позицию не выполнен: слабый импульс вверх.
|
||||||
|
```
|
||||||
|
|
||||||
|
Заголовок остаётся коротким, а смысл раскрывается в сообщении.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Изменения в архитектуре
|
||||||
|
|
||||||
|
## Strategy Layer
|
||||||
|
|
||||||
|
`TrendStrategy` теперь не только формирует торговый сигнал, но и объясняет причины отказа от входа.
|
||||||
|
|
||||||
|
Добавлены диагностические payload-поля:
|
||||||
|
|
||||||
|
- `entry_block_reason`
|
||||||
|
- `entry_block_message`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auto Runtime Layer
|
||||||
|
|
||||||
|
`AutoTradeService` теперь синхронизирует entry diagnostics в runtime state и журнал.
|
||||||
|
|
||||||
|
Добавлено антиспам-логирование причин не входа.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auto State Layer
|
||||||
|
|
||||||
|
`AutoTradeState` расширен полями диагностики входа:
|
||||||
|
|
||||||
|
- `entry_block_reason`
|
||||||
|
- `entry_block_message`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auto UI Layer
|
||||||
|
|
||||||
|
На экран автоторговли добавлено отображение причины не входа.
|
||||||
|
|
||||||
|
Также execution diagnostics приведён к более понятному стилю.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Journal Layer
|
||||||
|
|
||||||
|
Добавлено событие:
|
||||||
|
|
||||||
|
- `entry_blocked`
|
||||||
|
|
||||||
|
Событие пишет только изменение причины отказа от входа, а не каждый HOLD-цикл.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Что изменилось для пользователя
|
||||||
|
|
||||||
|
Пользователь теперь видит не просто:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Сигнал HOLD
|
||||||
|
```
|
||||||
|
|
||||||
|
А получает объяснение:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Сигнал HOLD
|
||||||
|
Вход в позицию · слабый импульс вверх
|
||||||
|
```
|
||||||
|
|
||||||
|
или:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Сигнал HOLD
|
||||||
|
Вход в позицию · рынок сейчас не подходит для входа
|
||||||
|
```
|
||||||
|
|
||||||
|
Также пользователь может открыть журнал и увидеть, почему бот не входил в позицию в течение длительного времени.
|
||||||
|
|
||||||
|
Это особенно важно для paper trading и подготовки к реальной торговле.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Почему это важно для стратегии
|
||||||
|
|
||||||
|
До этого этапа было трудно отличить нормальное ожидание от проблемы.
|
||||||
|
|
||||||
|
Теперь можно понять:
|
||||||
|
|
||||||
|
- стратегия слишком строгая
|
||||||
|
- market filter слишком часто блокирует вход
|
||||||
|
- live threshold слишком высокий
|
||||||
|
- direction ratio слишком требовательный
|
||||||
|
- не хватает накопленных live-данных
|
||||||
|
- execution layer блокирует уже готовый сигнал
|
||||||
|
|
||||||
|
Это создаёт основу для дальнейшей настройки торговой стратегии не на ощущениях, а по фактическим причинам отказа от входа.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Что подготовлено дальше
|
||||||
|
|
||||||
|
Этап подготовил основу для следующих работ:
|
||||||
|
|
||||||
|
- анализ частоты причин отказа от входа
|
||||||
|
- adaptive thresholds
|
||||||
|
- настройка чувствительности TrendStrategy
|
||||||
|
- очистка `_price_window` при смене актива
|
||||||
|
- signal aging / signal reset
|
||||||
|
- multi-symbol runtime isolation
|
||||||
|
- entry diagnostics filters в журнале
|
||||||
|
- статистика HOLD-причин
|
||||||
|
- AI-комментарии по причинам не входа
|
||||||
Reference in New Issue
Block a user