- BrainTools - https://www.braintools.ru -
Исходный код опубликован в этом репозитории на GitHub [1]

Телеграм полон каналов, публикующих торговые рекомендации с указанием цены входа в покупку или продажу криптовалюты. Прежде чем следовать любому из них, имеет смысл протестировать их сигналы на исторических данных.

После выгрузки сигналов в файл и проведения анализа становится заметна закономерность: повторяющиеся последовательности, в которых правильным решением было бы открытие позиции в противоположном направлении.

Автор канала — настоящий мастер своего дела: в январе 2026 года все 8 из 8 SHORT-сигналов по TRXUSDT резко двинулись в противоположную сторону в течение 45 минут после публикации. Но действительно ли это именно автор как человек?
Множители шагов между уровнями тейк-профита всегда одинаковы: ×1.52 → ×1.74 → ×1.47 → ×1.50. Соотношение T5/SL всегда равно 1.34. Эта рекомендация явно сгенерирована торговым алгоритмом. Но это ещё не самое интересное.

За пятнадцать минут до каждого поста на графике появляется аномалия объёма: большая синяя свеча в 10:00. Пост публикуется в 10:15. Затем ещё одна свеча ровно в 10:30.

SHORT-рекомендация с плечом x25 размещается точно на низу 4-часовой свечи (зелёная линия).
Используя приведённые выше критерии, мы инвертируем рекомендацию и входим против предложенного направления. Для сигнала №7 движение произошло, однако его не хватило, чтобы перевести позицию в безубыток.

Вот ценовой график с тем, что произошло после каждой SHORT-рекомендации с плечом x25. Цена всегда двигалась в противоположную сторону, вопрос лишь как сильно. Тут движение принёсло 0.5% от входа, бот не вышел так как комиссия 0.4%

PNL на скриншотах чистый, комиссия биржы учтена
Portfolio PNL: 8.54%
Portfolio Sharpe: 1.08
Avg Peak PNL: 1.44%
Avg Max Drawdown PNL: −0.48%
addStrategySchema({
strategyName: "jan_2026_strategy",
getSignal: async (symbol, when, currentPrice) => {
const signal = getActiveSignal(symbol, when);
if (!signal) {
return null;
}
const close_1m = await getClosePrice(symbol, "1m");
if (close_1m < signal.entry.from || close_1m > signal.entry.to) {
return null;
}
const [close_4h_prev, close_4h_cur] = await getCandles(symbol, "4h", 2);
const range_high = Math.max(close_4h_prev.high, close_4h_cur.high);
const range_low = Math.min(close_4h_prev.low, close_4h_cur.low); // fix: min, not max
const range_middle = (range_high + range_low) / 2; // fix: division applies to sum
const position = close_1m > range_middle ? "short" : "long";
return {
position,
...Position.moonbag({
position,
currentPrice,
percentStopLoss: HARD_STOP,
}),
minuteEstimatedTime: 24 * 60,
note: signal.note,
};
},
});
listenActivePing(async ({ symbol, data }) => {
const peakProfitDistance = await getPositionHighestProfitDistancePnlPercentage(symbol);
const currentProfit = await getPositionPnlPercent(symbol);
if (currentProfit < 0) {
return;
}
if (peakProfitDistance < TRAILING_TAKE) {
return;
}
Log.info("position closed due to the trailing take", {
symbol,
data,
});
await commitClosePending(symbol, {
id: "unknown",
note: str.newline(
"# Позиция закрыта по trailing take",
),
});
});
listenActivePing(async ({ symbol, data }) => {
const peakProfitCost = await getPositionHighestPnlPercentage(symbol);
const peakProfitMinutes = await getPositionHighestProfitMinutes(symbol);
if (peakProfitCost < PEAK_STALENESS_SINCE_PROFIT) {
return;
}
if (peakProfitMinutes < PEAK_STALENESS_SINCE_MINUTES) {
return;
}
Log.info("position closed due to the peak staleness", {
symbol,
data,
});
await commitClosePending(symbol, {
id: "unknown",
note: str.newline(
"# Позиция закрыта по peak staleness",
),
});
});
Не является торговой рекомендацией
Автор: tripolskypetr
Источник [2]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/29459
URLs in this post:
[1] в этом репозитории на GitHub: https://github.com/tripolskypetr/backtest-kit/tree/master/example
[2] Источник: https://habr.com/ru/articles/1028592/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1028592
Нажмите здесь для печати.