Дисклеймер: Информация в этой статье предоставлена исключительно в образовательных и ознакомительных целях и не является финансовым, инвестиционным или торговым советом. Торговля криптовалютами сопряжена с высоким риском убытков.
Подпишитесь на нашу рассылку, чтобы получать эксклюзивную аналитику по AI-трейдингу и обновления платформы.
Статья 6 из серии «Бэктесты без иллюзий»
Вы запустили study.optimize(), Optuna нашла набор параметров с PnL +87%. Вы радуетесь и готовите стратегию к продакшену. Через две недели живой торговли PnL около нуля. Что случилось?
Оптимизатор нашёл остриё иглы в пространстве параметров. Параметры идеально подогнаны под историческую последовательность сделок — но малейшее отклонение рыночных условий разрушает всю конструкцию. Это классический overfitting, и его можно было обнаружить до запуска.
В предыдущей статье мы сравнивали координатный спуск с байесовской оптимизацией и показали, почему Optuna находит оптимум эффективнее. Сегодня — следующий шаг: как убедиться, что найденный оптимум робастный, а не результат подгонки под шум.
Почему найти «лучшие» параметры — только половина работы
Оптимизация параметров стратегии — это поиск точки максимума в многомерном пространстве. Проблема в том, что максимум бывает двух типов:
Плато (plateau) — широкая плоская область, где PnL стабильно высок при вариациях параметров. Даже если рыночные условия сдвинут эффективные параметры на 10-20%, стратегия продолжит зарабатывать.
Острый пик (sharp peak) — узкая вершина, где PnL высок только при точном значении параметра. Сдвиг на один шаг обрушивает доходность. Это почти наверняка overfitting: оптимизатор нашёл артефакт исторических данных, а не устойчивую закономерность.
Метафора из альпинизма: плато — это горное плоскогорье, на котором можно безопасно ходить. Острый пик — это вершина иглы, на которой можно только балансировать.
Sharp peak vs flat plateau — визуальная интуиция
Представьте контурную карту, где оси — два параметра стратегии, а цвет — PnL. Два паттерна легко различить визуально:
Плато (робастный оптимум):
Широкие области одного цвета
Плавные переходы между уровнями PnL
Изолинии далеко друг от друга
При сдвиге от оптимума на ±20% PnL меняется не более чем на 10%
Представьте тепловую карту: в центре — яркий жёлтый прямоугольник размером примерно треть всей карты. Цвет плавно переходит в оранжевый, затем красный к краям. Оптимум — не точка, а регион.
Острый пик (overfitting):
Узкое яркое пятно, окружённое холодными цветами
Резкие переходы: рядом с оптимумом — провал
Изолинии сжаты в тесные кольца
При сдвиге на ±5% PnL падает на 50% и более
Представьте ту же тепловую карту, но в центре — крошечная жёлтая точка, немедленно окружённая синим и фиолетовым. Единственная «правильная» комбинация параметров.
Parameter sensitivity analysis
Одномерный анализ: PnL vs один параметр
Простейший способ — зафиксировать все параметры, кроме одного, и посмотреть, как PnL зависит от его значения. Optuna предоставляет для этого plot_slice:
import optuna
from optuna.visualization import plot_slice
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=500)
fig = plot_slice(study, params=["htf_entry_sell", "ltf_momentum", "stop_loss_pct"])
fig.show()
Что смотреть на slice plot:
Робастный параметр: облако точек образует широкую горизонтальную полосу вблизи оптимума. Лучшие trial-ы разбросаны по широкому диапазону значений параметра.
Хрупкий параметр: лучшие trial-ы сконцентрированы в узком диапазоне. Сдвиг параметра на один-два шага — и доходность обрушивается.
Двумерный анализ: contour plots (heatmaps)
Contour plot показывает взаимодействие двух параметров одновременно. Это ключевой инструмент plateau analysis, потому что параметры редко действуют независимо — пороги входа и выхода, таймфреймы и размеры позиции взаимосвязаны.
from optuna.visualization import plot_contour
fig = plot_contour(study, params=["htf_entry_sell", "htf_exit_buy"])
fig.show()
Contour plot для робастной пары параметров выглядит как топографическая карта холмистой равнины: плавные широкие изолинии, большие области одного цвета. Contour plot для хрупкой пары — как карта вулканического конуса: тесные концентрические кольца вокруг одной точки.
Для стратегии с 12 параметрами разделения это даёт (212)=66 попарных contour plots. Не обязательно изучать все — начните с параметров, которые Optuna оценила как наиболее важные.
Многомерный анализ: parameter importance ranking
Optuna умеет оценивать вклад каждого параметра в целевую функцию:
from optuna.visualization import plot_param_importances
fig = plot_param_importances(study)
fig.show()
График важности параметров — это горизонтальная гистограмма. Параметры ранжированы по убыванию их вклада в вариацию PnL. Первые 3-4 параметра обычно объясняют 70-80% вариации.
Правило: если параметр объясняет менее 2% вариации PnL, его значение практически не важно для результата — он робастный по определению. Фокусируйте plateau analysis на топ-5 наиболее важных параметров.
Результат — сетка точечных графиков. Каждый подграфик показывает значение целевой функции (PnL, ось Y) против значения одного параметра (ось X). Точки — отдельные trial-ы. Для робастного параметра лучшие точки (верхние по PnL) распределены по широкому диапазону X. Для хрупкого — сгруппированы в узком столбце.
plot_contour — двумерные контуры
from optuna.visualization import plot_contour
important_pairs = [
["htf_entry_sell", "htf_entry_buy"],
["htf_entry_sell", "stop_loss_pct"],
["ltf_momentum_threshold", "take_profit_pct"],
]
for params in important_pairs:
fig = plot_contour(study, params=params)
fig.update_layout(title=f"Contour: {params[0]} vs {params[1]}")
fig.show()
Каждый contour plot — это тепловая карта с двумя параметрами по осям. Цвет кодирует средний PnL в данной области пространства параметров. Жёлтый/зелёный — высокий PnL, синий/фиолетовый — низкий. Изолинии соединяют точки с одинаковым PnL.
fANOVA (functional ANOVA) декомпозирует вариацию целевой функции по параметрам и их взаимодействиям. Это мощнее, чем простая корреляция, потому что учитывает нелинейные эффекты.
Количественные метрики плато
Визуальная оценка субъективна. Нужны числа. Вот три метрики, которые формализуют понятие «плато».
Sensitivity ratio
Отношение изменения PnL к изменению параметра:
Si=Δpi/pi,optΔPnL/PnLopt
где ΔPnL — падение PnL при отклонении параметра pi от оптимума на Δpi.
Интерпретация:
Si<0.5 — параметр робастный: 10% сдвиг даёт менее 5% падения PnL
0.5≤Si<2.0 — умеренная чувствительность
Si≥2.0 — параметр хрупкий: 10% сдвиг обрушивает PnL на 20%+
Plateau width
Ширина области параметра, внутри которой PnL остаётся в пределах X% от оптимума:
где знаменатель — полный диапазон поиска параметра.
Интерпретация:
Wirel(10%)>0.3 — плато покрывает более 30% диапазона при пороге 10%. Робастный параметр.
Wirel(10%)<0.05 — плато уже 5% диапазона. Красный флаг.
Robustness score
Комбинированная метрика по всем параметрам:
R=∏i=1k(Wirel(10%))wi
где wi — нормализованная важность параметра i из fANOVA (∑wi=1).
Произведение взвешенных ширин — строгая метрика: если хотя бы один важный параметр имеет узкое плато, R будет низким. Неважные параметры (с малым wi) почти не влияют.
Интерпретация:
R>0.1 — стратегия робастна
0.01<R≤0.1 — требуется дополнительная проверка (walk-forward)
R≤0.01 — overfitting весьма вероятен
Python-код для автоматизированного plateau detection
import numpy as np
import optuna
from optuna.importance import FanovaImportanceEvaluator
from typing importDict, List, Tupledefcompute_sensitivity_ratio(
study: optuna.Study,
param_name: str,
n_steps: int = 20,
) -> float:
"""
Вычисляет sensitivity ratio для одного параметра.
Фиксирует все параметры на лучших значениях, варьирует param_name,
оценивает падение PnL через интерполяцию trial-ов.
"""
best_trial = study.best_trial
best_value = best_trial.values[0]
best_param = best_trial.params[param_name]
all_trials = [t for t in study.trials if t.state == optuna.trial.TrialState.COMPLETE]
all_trials.sort(key=lambda t: t.values[0], reverse=True)
top_trials = all_trials[:max(10, len(all_trials) // 5)]
param_values = np.array([t.params[param_name] for t in top_trials])
pnl_values = np.array([t.values[0] for t in top_trials])
if best_param == 0or best_value == 0:
returnfloat('inf')
from numpy.polynomial import polynomial as P
coeffs = np.polyfit(param_values, pnl_values, deg=2)
dpnl_dparam = 2 * coeffs[0] * best_param + coeffs[1]
sensitivity = abs(dpnl_dparam * best_param / best_value)
return sensitivity
defcompute_plateau_width(
study: optuna.Study,
param_name: str,
threshold_pct: float = 10.0,
) -> Tuple[float, float]:
"""
Вычисляет абсолютную и относительную ширину плато.
Returns:
(absolute_width, relative_width)
"""
best_value = study.best_value
threshold = best_value * (1 - threshold_pct / 100)
trials = [t for t in study.trials if t.state == optuna.trial.TrialState.COMPLETE]
good_trials = [t for t in trials if t.values[0] >= threshold]
ifnot good_trials:
return0.0, 0.0
good_params = [t.params[param_name] for t in good_trials]
all_params = [t.params[param_name] for t in trials]
plateau_min = min(good_params)
plateau_max = max(good_params)
absolute_width = plateau_max - plateau_min
search_range = max(all_params) - min(all_params)
relative_width = absolute_width / search_range if search_range > 0else0return absolute_width, relative_width
defcompute_robustness_score(
study: optuna.Study,
threshold_pct: float = 10.0,
) -> Dict:
"""
Вычисляет комбинированный robustness score.
Returns:
dict с per-parameter метриками и итоговым score
"""
evaluator = FanovaImportanceEvaluator()
importances = optuna.importance.get_param_importances(
study, evaluator=evaluator
)
results = {}
total_importance = sum(importances.values())
for param_name, importance in importances.items():
sensitivity = compute_sensitivity_ratio(study, param_name)
abs_width, rel_width = compute_plateau_width(
study, param_name, threshold_pct
)
weight = importance / total_importance
results[param_name] = {
"importance": importance,
"weight": weight,
"sensitivity_ratio": sensitivity,
"plateau_width_abs": abs_width,
"plateau_width_rel": rel_width,
}
log_score = sum(
r["weight"] * np.log(max(r["plateau_width_rel"], 1e-10))
for r in results.values()
)
robustness_score = np.exp(log_score)
return {
"robustness_score": robustness_score,
"parameters": results,
"verdict": (
"robust"if robustness_score > 0.1else"check"if robustness_score > 0.01else"overfitting"
),
}
Рассмотрим три стратегии с 12 параметрами разделения (separation parameters). Каждая стратегия прошла оптимизацию Optuna с 500 trial-ами.
Strategy A (~55% PnL, ~500 trades, ~15% time)
Параметры Strategy A формируют широкое плато. Возьмём ключевой параметр htf_entry_sell:
Оптимальное значение: 0.020
PnL при 0.015: +51% (падение 7%)
PnL при 0.025: +49% (падение 11%)
PnL при 0.010: +43% (падение 22%)
PnL при 0.030: +41% (падение 25%)
Если представить это как одномерный график (ось X — значение htf_entry_sell, ось Y — PnL), вы увидите пологую параболу с плоской вершиной. Диапазон 0.010–0.030 — это плато, где PnL остаётся в пределах ±25% от оптимума.
Sensitivity ratio: S=0.250.11=0.44 — робастный.
Plateau width при пороге 10%: от 0.013 до 0.027, Wrel=0.040.014=35%.
Strategy B (~25% PnL, ~40 trades, ~5% time)
Strategy B оптимизирована на малом количестве сделок. Параметр htf_entry_sell:
Оптимальное значение: 0.018
PnL при 0.015: +24% (падение 4%)
PnL при 0.025: +9% (падение 64%)
PnL при 0.012: +11% (падение 56%)
На графике — асимметричная и крутая кривая. Плато существует только в узком диапазоне 0.015–0.020. Справа от оптимума — обрыв.
Sensitivity ratio: S=0.390.64=1.64 — умеренная чувствительность, но при 40 сделках это красный флаг. Малая выборка + узкое плато = высокая вероятность overfitting.
Plateau width при пороге 10%: от 0.016 до 0.020, Wrel=0.040.004=10%.
Strategy C (~300% PnL, ~400 trades, ~45% time)
Strategy C показывает потрясающий PnL, но анализ плато выявляет проблемы:
Оптимальное значение htf_entry_sell: 0.022
PnL при 0.020: +295% (падение 2%)
PnL при 0.025: +142% (падение 53%)
PnL при 0.019: +128% (падение 57%)
На графике — характерная «игла»: очень высокий пик при 0.022, резкое падение во все стороны. Контурный plot покажет яркое пятно, немедленно окружённое холодными цветами.
Sensitivity ratio: S=0.140.53=3.79 — хрупкий. Несмотря на 400 сделок, стратегия чрезмерно зависит от точного значения одного параметра.
Plateau width при пороге 10%: от 0.021 до 0.023, Wrel=0.040.002=5%.
Сводная таблица
Стратегия
PnL
Trades
Sensitivity
Plateau width
Robustness score
Verdict
Strategy A
+55%
~500
0.44
35%
0.148
Robust
Strategy B
+25%
~40
1.64
10%
0.032
Check (малая выборка)
Strategy C
+300%
~400
3.79
5%
0.008
Overfitting
Парадокс: Strategy C с PnL +300% имеет наихудший robustness score. Strategy A с «скромными» +55% — наиболее робастна. Это типичный результат plateau analysis: яркие цифры часто маскируют хрупкость.
Доверительные интервалы для каждой стратегии можно дополнительно проверить через Monte Carlo bootstrap — он покажет разброс PnL при ресемплинге сделок.
3D-визуализация и тепловые карты
Для наиболее важных пар параметров полезно построить 3D-поверхность и тепловую карту. Это даёт интуитивное понимание формы ландшафта.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
defplot_parameter_landscape(
study: "optuna.Study",
param_x: str,
param_y: str,
grid_size: int = 50,
):
"""
Строит 3D surface plot и heatmap для пары параметров.
"""
trials = [t for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE]
x_vals = np.array([t.params[param_x] for t in trials])
y_vals = np.array([t.params[param_y] for t in trials])
z_vals = np.array([t.values[0] for t in trials])
from scipy.interpolate import griddata
xi = np.linspace(x_vals.min(), x_vals.max(), grid_size)
yi = np.linspace(y_vals.min(), y_vals.max(), grid_size)
Xi, Yi = np.meshgrid(xi, yi)
Zi = griddata((x_vals, y_vals), z_vals, (Xi, Yi), method='cubic')
fig = plt.figure(figsize=(18, 7))
ax1 = fig.add_subplot(121, projection='3d')
surf = ax1.plot_surface(Xi, Yi, Zi, cmap=cm.viridis, alpha=0.85,
edgecolor='none')
ax1.set_xlabel(param_x)
ax1.set_ylabel(param_y)
ax1.set_zlabel('PnL, %')
ax1.set_title('3D Parameter Landscape')
fig.colorbar(surf, ax=ax1, shrink=0.5)
ax2 = fig.add_subplot(122)
hm = ax2.pcolormesh(Xi, Yi, Zi, cmap=cm.viridis, shading='auto')
contours = ax2.contour(Xi, Yi, Zi, levels=10, colors='white',
linewidths=0.8, alpha=0.7)
ax2.clabel(contours, inline=True, fontsize=8, fmt='%.0f%%')
best = study.best_trial
ax2.scatter(best.params[param_x], best.params[param_y],
color='red', s=100, marker='*', zorder=5, label='Optimum')
ax2.set_xlabel(param_x)
ax2.set_ylabel(param_y)
ax2.set_title('Contour Heatmap')
ax2.legend()
fig.colorbar(hm, ax=ax2)
plt.tight_layout()
plt.savefig(f'landscape_{param_x}_vs_{param_y}.png', dpi=150)
plt.show()
3D surface plot для робастной стратегии напоминает столовую гору — плоская вершина с пологими склонами. Для хрупкой стратегии — остроконечный пик, как Маттерхорн. Heatmap дополняет 3D-вид, показывая ту же информацию в проекции сверху с изолиниями.
Red flags: когда результаты оптимизации подозрительны
Восемь признаков того, что оптимизация нашла overfitting, а не реальную закономерность:
1. Sensitivity ratio > 2 для ключевого параметра
Если PnL падает более чем на 20% при 10%-ном сдвиге параметра — оптимум хрупкий.
2. Plateau width < 10% диапазона поиска
Если «хорошая» область занимает менее 10% от исследованного диапазона — оптимизатор, вероятнее всего, нашёл артефакт.
3. Топ-3 trial-а дают PnL в 2-3 раза выше медианы
Если лучшие trial-ы — выбросы на фоне остальных, а не «верхушка холма» — это не плато.
top_3_mean = np.mean(sorted([t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE],
reverse=True)[:3])
median_pnl = np.median([t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE])
outlier_ratio = top_3_mean / median_pnl
if outlier_ratio > 2.5:
print(f"WARNING: Top trials are {outlier_ratio:.1f}x above median — possible overfitting")
4. Малое количество сделок (< 50) при высоком PnL
Малая выборка + высокий PnL = высокая дисперсия оценки. Plateau analysis на 40 сделках ненадёжен сам по себе. Для таких стратегий критически важен Monte Carlo bootstrap.
5. Одна «магическая» комбинация параметров
Если contour plot показывает единственную яркую точку среди серого поля — это не стратегия, а подогнанная под данные комбинация.
6. Слишком много параметров
Для 12 параметров с 10 значениями каждый пространство поиска содержит 1012 комбинаций. Optuna исследует ~500. Вероятность найти «хороший» артефакт в таком пространстве — высока. Чем больше параметров, тем строже должен быть plateau analysis.
7. PnL резко падает на out-of-sample
Если in-sample PnL +87%, а walk-forward показывает +12% — оптимизация подогнала параметры под тренировочный период. Подробнее об этом — в статье о Walk-Forward оптимизации.
8. Параметры «прижаты» к границам диапазона
Если оптимальное значение совпадает с границей поисковой сетки — оптимум, возможно, находится за пределами диапазона. Расширьте диапазон и перезапустите оптимизацию.
Автоматический отчёт plateau analysis
Собираем всё вместе в один отчёт, который генерируется после каждой оптимизации:
import json
from datetime import datetime
defgenerate_plateau_report(
study: "optuna.Study",
strategy_name: str,
n_trades: int,
threshold_pct: float = 10.0,
) -> dict:
"""
Генерирует полный отчёт plateau analysis.
"""
robustness = compute_robustness_score(study, threshold_pct)
red_flags = []
sorted_params = sorted(
robustness["parameters"].items(),
key=lambda x: x[1]["importance"],
reverse=True
)
for name, metrics in sorted_params[:3]:
if metrics["sensitivity_ratio"] > 2.0:
red_flags.append(
f"High sensitivity for {name}: "f"S={metrics['sensitivity_ratio']:.2f}"
)
for name, metrics in robustness["parameters"].items():
if metrics["plateau_width_rel"] < 0.05:
red_flags.append(
f"Narrow plateau for {name}: "f"W={metrics['plateau_width_rel']:.1%}"
)
all_values = sorted(
[t.values[0] for t in study.trials
if t.state == optuna.trial.TrialState.COMPLETE],
reverse=True
)
iflen(all_values) > 10:
top3 = np.mean(all_values[:3])
med = np.median(all_values)
if med > 0and top3 / med > 2.5:
red_flags.append(
f"Top trials are outliers: "f"{top3:.1f} vs median {med:.1f} "f"({top3/med:.1f}x)"
)
if n_trades < 50:
red_flags.append(f"Low trade count: {n_trades}")
report = {
"strategy": strategy_name,
"timestamp": datetime.now().isoformat(),
"best_pnl": study.best_value,
"n_trials": len(study.trials),
"n_trades": n_trades,
"robustness_score": robustness["robustness_score"],
"verdict": robustness["verdict"],
"red_flags": red_flags,
"parameters": robustness["parameters"],
}
return report
report = generate_plateau_report(
study, strategy_name="Strategy A", n_trades=491
)
print(json.dumps(report, indent=2, default=str))
Plateau analysis и walk-forward validation (WFO) — комплементарные методы:
Plateau analysis отвечает на вопрос: «Насколько устойчив оптимум к небольшим сдвигам параметров?» Это проверка параметрической робастности.
Walk-forward отвечает на вопрос: «Работают ли параметры на данных, которых оптимизатор не видел?» Это проверка временной робастности.
Стратегия может пройти plateau analysis (широкое плато), но провалить walk-forward (рыночный режим изменился). И наоборот — может пройти walk-forward на фиксированных параметрах, но иметь хрупкий оптимум.
Рекомендация: всегда используйте оба метода. Если стратегия прошла plateau analysis (R>0.1) и walk-forward (PnLOOS>50%×PnLIS) — это сильный сигнал робастности. Подробнее — в статье о Walk-Forward оптимизации.
Для оценки доверительных интервалов PnL на каждом этапе применяйте Monte Carlo bootstrap. А для корректного сравнения стратегий с разным активным временем — метрику PnL по активному времени.
Рекомендации
Перед оптимизацией
Ограничьте число параметров. Чем меньше параметров — тем надёжнее плато. 5-7 параметров — разумный максимум. 12 — уже требует повышенной осторожности.
Задавайте осмысленные диапазоны. Не ставьте htf_entry_sell от 0.001 до 1.0, если реалистичный диапазон — 0.005 до 0.05. Широкие бессмысленные диапазоны создают иллюзию плато.
Используйте достаточно trial-ов. Для 12 параметров минимум 300-500 trial-ов. Для надёжного plateau analysis — 1000+.
Во время оптимизации
Следите за convergence. Если Optuna продолжает находить значительно лучшие решения после 400 trial-ов — процесс не сошёлся, и plateau analysis будет ненадёжным.
Используйте pruning с осторожностью. Aggressive pruning (MedianPruner) может отсекать trial-ы, которые выглядят плохо на начальных шагах, но важны для построения полной картины ландшафта.
После оптимизации
Генерируйте plateau report автоматически. Встройте generate_plateau_report() в пайплайн оптимизации. Не полагайтесь на визуальную оценку — используйте числа.
Проверяйте top-5 параметров. Если fANOVA показывает, что 3 параметра объясняют 80% вариации — остальные 9 можно проверять менее тщательно.
Сравнивайте с базовой стратегией. Если стратегия с дефолтными параметрами (без оптимизации) показывает +30%, а оптимизированная +55% — разница всего 25 п.п., и плато, скорее всего, широкое. Если дефолтная — 0%, а оптимизированная +300% — вся доходность зависит от точной подгонки параметров.
Финальная проверка — walk-forward. Plateau analysis — необходимое, но недостаточное условие робастности. Обязательно валидируйте out-of-sample.
Заключение
Оптимизация параметров — мощный инструмент, но без plateau analysis это игра в рулетку. Вы не знаете, нашли вы устойчивую закономерность или подогнали модель под шум.
Три правила plateau analysis:
Считайте robustness score. Произведение взвешенных ширин плато даёт одно число, которое суммирует робастность всех параметров. R>0.1 — зелёный свет.
Sensitivity ratio < 1 для ключевых параметров. Если 10% сдвиг параметра вызывает менее 10% падение PnL — параметр робастный. Если больше — будьте осторожны.
Визуализируйте contour plots. Никакая метрика не заменит понимания формы ландшафта. Плоская столовая гора — хорошо. Остроконечная игла — плохо.
Plateau analysis занимает 5 минут после оптимизации и может сэкономить недели убыточной торговли в продакшене. Это обязательный шаг между study.optimize() и запуском бота.
@article{soloviov2026plateauanalysis,
author = {Soloviov, Eugen},
title = {Plateau analysis: как отличить робастный оптимум от overfitting},
year = {2026},
url = {https://marketmaker.cc/ru/blog/post/plateau-analysis-overfitting},
version = {0.1.0},
description = {Почему найти лучшие параметры стратегии — только половина работы. Как визуально и количественно отличить устойчивое плато от хрупкого пика, и почему Optuna contour plots — обязательный шаг перед запуском оптимизированной стратегии в продакшен.}
}