Если вы, как и я, пробовали инвестировать — покупали и продавали ценные бумаги по наитию или рандому, то вам сюда. Тут мы начнем выстраивать наши хаотические метания в систему для генерирования денег.
Я ни разу не профессиональный инвестор и экономического образования не получал, но стараюсь выстроить стратегию битвы с биржевым рынком для получения прибыли.
Всем привет. Цикл статей был переименован, вы могли меня раньше читать под названием “Инвестиционные боты (почти) с нуля”. Статьи были скучноваты, поэтому эта статья — небольшой эксперимент. Но хватит отвлекаться, погнали!
Чтобы понять, когда что-то покупать или продавать, нужно, чтобы кто-то тебе говорил, что сейчас хорошее время для этого. Этим кем-то будут выступать сигналы.
Сигналы должны анализировать состояние рынка и выдавать три различных сообщения: покупай, продавай, сиди на попе ровно.
Риски
Не существует ни одного 100% работающего сигнала, что бы вы ни придумали, рынок все равно вас обыграет и заберет себе часть прибыли. Нужно быть готовым к этому.
Тут я спросил у Грока, какой процент успеха считается хорошим, и получил неожиданный ответ. “40–45% успешных сделок — это обычный результат, 48–52% — это уже хороший результат.”
Что? Это же чистый рандом. Как 50% успеха может считаться хорошим результатом? Ведь если я просто случайно буду делать сделки, не думая, то половина из них будет в плюсе, половина в минусе (если пренебречь комиссией и нулевыми сделками).
Но объяснение тут простое — кроме успешности сделки в расчет нужно брать очень важный показатель, а именно соотношение потери при неудаче и прибыли при выигрыше.
Такое соотношение принято называть R/R (от английского risk-reward) и обозначать через двоеточие, к примеру 1:2, что значит, что прибыль должна быть в 2 раза больше, чем возможные потери.
И вот тут уже становится все на свои места. Если винрейт у нас 50% при R/R 1:2, то мы в стабильном плюсе.
Хорошей стратегией в итоге становится стратегия с винрейтом 45-60% при R/R 1:2 — 1:3. При увеличении процента побед обычно падает возможная прибыль (менее рискованно и менее прибыльно). И наоборот, можно выбрать более рискованную стратегию с винрейтом ниже 40%, но при R/R 1:4.
Вам уже интересно, какие боты получатся у меня? Мне очень! Поэтому погнали дальше.
Я уже дважды обещал рассказать про сигнал пересечения скользящих средних. Наконец-то это время пришло.
Пересечение скользящих средних (Moving Average Crossover)
Вы уже знаете, что такое скользящие средние? Да? Возьмите с полки пирожок. Если нет, то можете почитать мою предыдущую скучную статью о скользящих средних
Инвестиционные боты (почти) с нуля. Часть 2: свечи и индикаторы
Но вы вряд ли будете её читать — скучная теория, поэтому вкратце: все скользящие средние — это, как бы банально это ни звучало, усреднение цены за последние несколько интервалов времени по каким-то правилам. Правил огромное множество, я реализовал и рассказал в предыдущей статье только о 5 из них, и любую скользящую среднюю можно использовать как основу для сигнала пересечения скользящих.
В общем виде все сигналы пересечения скользящих средних опираются на построение двух графиков скользящих средних (Moving Average) MA — длинной и короткой. Для длинной MA берется более долгий промежуток времени, для короткой, соответственно, короткий промежуток.
На основе этого пересечения можно сгенерировать сигнал:
-
на покупку — если короткая MA пересекает длинную MA снизу вверх, то это может означать смену тренда: цена начала расти быстрее, чем в среднем за более длинный период.
-
на продажу — если короткая MA пересекает длинную MA сверху вниз. Это сигнализирует о начале нисходящего тренда — цена падает.
-
ожидание — во всех прочих ситуациях
Вот, к примеру, хорошее отображение того, как можно было заработать. На скрине есть 2 пересечения. Сначала 20 ноября короткая EHMA9 пересекает EHMA20 вниз и цена падает, потом пересекает вверх и цена так же стремительно растёт.
Также у этого сигнала есть дополнительный фильтр — дистанция — то, как сильно отдалился один график от второго, обычно в процентах. Если дистанция слишком маленькая, то это может быть боковой тренд и его нужно игнорировать.
+14714% или +88% или -25% годовых?
Хватит теории, пора и проверить на деле, что получается.
Для начала я сделал простенькую логику, которая возьмет свечи за предыдущие периоды и будет итеративно проверять сигнал, каждый раз добавляя по 1 свече, то есть будет эмулировать течение времени. Для каждого нового дня мы будем проверять наличие сигнала и стараться покупать или продавать (если есть что).
Естественно, тест не может полностью отразить действительность, так как существует много вещей, которые будут влиять на результат.
Тем не менее, вот входные параметры теста.
-
Актив — Банк ВТБ, BBG004730ZJ9
-
Начало теста 1 января 2025, конец 31 декабря 2025
-
Комиссия 0.05% от операции (Т-Банк тариф Трейдер)
-
Цена покупки и продажи = среднему значению между ценами открытия и закрытия
-
Не учитываем возможность проскальзывания и влияния своих продаж на рынок
-
Сигнал — пересечение скользящих EHMA9 и EHMA20, интервал — дни
-
Фильтр для покупки — дистанция 0.4%
-
Фильтр для продажи — отсутствует
-
Денег в портфеле на старте — 1 000 000 р.
Запускаем вычисления, немного ждем и получаем результат торгов.
В конце года получаем баланс 147140871.49.
Мельком глянул на цифру и подумал 47% как-то слишком хорошо для запуска, какой я классный инвестор. Но что-то не так, начинаю считать цифры и получается, что это не 1,5 млн, а 147 млн. Т.е. 14714% годовых.
Я, конечно, надеюсь, что я изобрел крутой алгоритм, но понимаю, что тут что-то не так. После выяснения деталей оказывается, что я забыл уменьшать баланс при каждой покупке и он только рос на продажах.
Что ж, исправляем и повторяем запуск. Результат уже более реальный и он приведен ниже в таблице.
|
Дата |
Цена сделки |
Количество |
Изменение |
Сумма на счете |
|
16.01.2025 |
84.56 |
11944 |
-999 973,66 |
26,34 |
|
28.01.2025 |
84.66 |
-11944 |
1 003 630,01 |
1 003 656,36 |
|
14.02.2025 |
87.79 |
11609 |
-1 003 577,18 |
79,17 |
|
28.02.2025 |
91.7 |
-11609 |
1 048 290,70 |
1 048 369,87 |
|
12.04.2025 |
78.17 |
13505 |
-1 048 309,32 |
60,55 |
|
11.05.2025 |
99.07 |
-13505 |
1 335 449,12 |
1 335 509,67 |
|
14.06.2025 |
98.55 |
13572 |
-1 335 473,60 |
36,07 |
|
03.07.2025 |
99.94 |
-13572 |
1 373 817,05 |
1 373 853,12 |
|
20.07.2025 |
82.9 |
16519 |
-1 373 828,45 |
24,67 |
|
01.08.2025 |
76.68 |
-16519 |
1 276 940,67 |
1 276 965,34 |
|
08.10.2025 |
66.04 |
18945 |
-1 276 962,81 |
2,53 |
|
24.10.2025 |
67.28 |
-18945 |
1 280 799,08 |
1 280 801,61 |
|
21.11.2025 |
71.16 |
17884 |
-1 280 776,79 |
24,82 |
|
05.12.2025 |
73.17 |
-17884 |
1 299 606,09 |
1 299 630,91 |
В итоге 5 декабря мы получаем почти 1,3 млн, то есть 30% годовых. Но можно обратить внимание, что если бы мы остановились 3 июля, то получили бы 1,37 млн — это примерно 88% годовых. К такому нужно стремиться.
Звучит слишком шоколадно, учитывая, насколько глупая стратегия у нас была? Да, к сожалению, так оно и есть. Значения фильтров и индикаторы немного подобраны на бектесте для более красивых значений.
Реальные цифры для стратегии пересечения скользящих при использовании разных типов скользящих и дистанций в среднем лежат примерно от -25% годовых до +15%. Виден явный перекос в отрицательную сторону, поэтому нужно усложнять логику, чем мы с вами и займёмся в будущих частях.
Но я не унываю, это все-таки максимально глупый алгоритм, у которого есть проблемы и где еще много мест, которые можно дорабатывать. Главное в том, что если его верно настроить, то потенциал у него есть.
Страница с сигналами для всех активов
Это не основное направление проекта, а просто добавка для наглядности. Я ленивый и не хочу для каждого актива руками тыкать — хочется видеть картину сразу по всему рынку. У кого сейчас buy, у кого sell, кого игнорим. По сути скринер на минималках.
Сверху настройки: интервал (день, час, 15 минут) и один или несколько сигналов пересечения. Каждый сигнал — пара индикаторов плюс подтверждение: 1 бар, 2 бара или от 1 до 3 баров. По умолчанию подставляются EHMA9/SMA20 и EHMA9/HMA20 — те самые, которые в бэктесте показали себя «ну хотя бы не -25%».
Жмём Build — система пробегается по всем доступным инструментам, скачивает свечи и считает сигнал. Идёт в фоне, фронт раз в секунду спрашивает «ну как там?». 84/1856. 85/1856. 86/1856.
Сама проверка пересечения работает по последним 4 барам — смотрим, поменялись ли индикаторы местами и на каком именно баре:
function checkCross(barCount, lastBars) { if (barCount == 1) { if (lastBars.bar1 && !lastBars.bar2) return 1; if (!lastBars.bar1 && lastBars.bar2) return -1; } else if (barCount == 2) { if (lastBars.bar1 && lastBars.bar2 && !lastBars.bar3) return 1; if (!lastBars.bar1 && !lastBars.bar2 && lastBars.bar3) return -1; } else if (barCount == 3) { if (lastBars.bar1 && lastBars.bar2 && lastBars.bar3 && !lastBars.bar4) return 1; if (!lastBars.bar1 && !lastBars.bar2 && !lastBars.bar3 && lastBars.bar4) return -1; } return 0;}
Подтверждение на 2-3 бара отсекает часть ложных срабатываний на боковике. Правда, так мы упускаем момент и может быть слишком поздно для входа.
Качать свечи по всем инструментам каждый раз — это медленно, и можно получить блок по рейт-лимиту. Поэтому кеш в памяти:
async function getCandlesCached(figi, interval) { if (!Mars.cache.Candles) Mars.cache.Candles = {}; if (!Mars.cache.Candles[interval]) Mars.cache.Candles[interval] = {}; const cached = Mars.cache.Candles[interval][figi]; if (cached) return { candles: cached, fromCache: true }; const candles = await Mars.services.GetCandles({ figi, interval }, Req); Mars.cache.Candles[interval][figi] = candles; return { candles, fromCache: false };}
По мере вычисления таблица с инструментами постепенно наполняется и можно просматривать сигналы. Зелёный buy, красный sell, прочерк — мимо кассы. Сортировка по любой колонке, поиск по названию, клик по строке открывает карточку инструмента сбоку. Всё как у взрослых.
Главная фишка — несколько сигналов одновременно. Если и EHMA9/SMA20 говорит buy, и EMA9/EMA21 тоже buy — это уже не один пьяный советчик, а целый консилиум пьяных советчиков. А когда они все согласны — это уже что-то.
Ограничения те же, о которых говорили выше: пересечение скользящих со всеми его болячками, плюс данные не в реальном времени. Для скальпинга не подойдёт — пока страница посчитает, рынок успеет три раза передумать. Для дневного таймфрейма — нормально.
Как по мне, уже вполне себе полезный продукт получается. Вопрос к вам интересна ли будет вам такая страница с сигналами, если я выложу ее в общий доступ?
Послесловие
Это продолжение серии постов Инвестиционные боты (почти) с нуля, которые вы можете найти в моем профиле. Серия переименована, а так же был создан телеграмм канал с более частыми апдейтами. Кому интересно, подписывайтесь https://t.me/divaninvest
ссылка на оригинал статьи https://habr.com/ru/articles/1041272/