Исходный код опубликован в этом репозитории на GitHub

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

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

Автор канала — настоящий мастер своего дела: в январе 2026 года все 8 из 8 SHORT-сигналов по TRXUSDT резко двинулись в противоположную сторону в течение 45 минут после публикации. Но действительно ли это именно автор как человек?

Расчехляем тамагочи

Множители шагов между уровнями тейк-профита всегда одинаковы: ×1.52 → ×1.74 → ×1.47 → ×1.50. Соотношение T5/SL всегда равно 1.34. Эта рекомендация явно сгенерирована торговым алгоритмом. Но это ещё не самое интересное.

https://www.reddit.com/r/PromptEngineering/comments/1sejh80/anthropic_hid_a_multiagent_tamagotchi_in_claude/

За пятнадцать минут до каждого поста на графике появляется аномалия объёма: большая синяя свеча в 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); 
    const range_middle = (range_high + range_low) / 2;

    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",
    ),
  });
});

Спасибо за внимание!

Не является торговой рекомендацией

Комментарии (1)