Ранее видел много публикаций и скептических комментариев на тему использования нейросетей в трейдинге, и хотелось бы поделиться своими наработками и мнением.
Всем, кто имеет большой опыт в торговле, знаком такой термин, как «тестирование стратегии на истории», а что, если я скажу, что с приходом к нам нейросетей мы можем тестировать наши стратегии на будущем?
То есть на будущем для нейросети и прошлом для нас. Такой метод будет наиболее эффективен для результатов, кроме того, мы можем использовать неограниченное количество индикаторов и выявлять те из них, которые бесполезны.
Например, таким образом я узнал, что RSI индикатор совершенно бесполезен в техническом анализе. Сильное заявление? :-)
Многие из вас, оцифровав и обучив нейросеть своей стратегией, могут сильно разочароваться, когда увидят, что результаты оставляют желать лучшего.
А какие-то индикаторы, которыми мы даже не пользовались, отнюдь покажут ошеломляющие результаты в обучении.
Для всех ищущих в индикаторах, в том числе нейросетевых, панацею и кнопку «бабло» отвечу сразу, что это всего лишь способы улучшить свое ��татистическое преимущество.
Любой индикатор не добавляет информации. Он берёт уже известные данные — цену, объём, диапазон — и пересчитывает их с задержкой, сглаживанием или нелинейным преобразованием.
Поэтому индикатор не может давать гарантированный результат. Он лишь немного смещает распределение вероятностей: в одних состояниях рынка вероятность исхода становится выше, в других — ниже.
Работа индикатора — не «предсказать», а слабым сигналом подсветить контекст: перегрев, инерцию, отсутствие направления, смену режима.
В изоляции любой индикатор бесполезен. Его статистическое преимущество слишком мало и легко перекрывается шумом, спредом и случайностью.
Преимущество появляется только тогда, когда: — индикатор используется в конкретном рыночном режиме — его выход встроен в систему ограничений — результат оценивается не по сделке, а по серии реализаций
(тут на первый план встает банальная дисциплина, с которой у большинства людей большие проблемы)
Даже тогда это не гарантия, а небольшой сдвиг математического ожидания. Рынок нельзя обыграть формулой.
Можно лишь аккуратно собрать систему, где сумма слабых факторов чуть чаще склоняет исход в твою сторону. И именно за этот небольшой сдвиг и идёт вся игра.
В этом посте я дам вам очень ценный способ, с помощью которого вы, дорогие программисты (или вайбкодеры, как я), сможете оцифровать свои стратегии, а также улучшить их, автоматизировать и использовать для улучшения своего статистического преимущества.
Начнем.
1 этап: подготовка данных обучающих и валидационных
На этом этапе вам необходимо найти максимальное количество рыночных данных в табличном виде: цена закрытия, открытия, максимум, минимум и объем, и кроме того, эти данные должны быть качественные.
Далее самый сложный момент во всей этой истории (да, да, создание и обучение нейросети, как бы красиво это не звучало, самое простое) — создать технологию определения точек на графике, которые будет учиться определять нейросеть.
Наиболее вероятно, что это будут некие точки в окрестностях экстремума, или у кого-то есть свои некие точки G, при входе в которую начинается супер прибыльная сделка.
Те, у кого есть стратегия, как правило, знают эти точки.
После долгого и мучительного определения по табличным данным этих точек, мы автоматизированно проставляем маркеры на всех наших исторических данных.
Важно: уберите несколько самых последних месяцев из данных, на них вы и будете смотреть результаты и сравнивать с реальностью.
Результат этого этапа — папка с сотнями таблиц с рыночными данными и проставленными маркерами классов. Например: 0 — ничего, 1 — дно, 2 — вершина. Или 0 — ничего, 1 — лонг, 2 — шорт, 3 — выход из позиции и т.п.
На этих данных будет обучаться наша нейросеть.
2 этап: выбор фич
На втором этапе нужно, чтобы алгоритм рассчитывал фичи (фичи — это параметры, на которые обращает внимание нейронка); в данном контексте для простоты понимания — фичи это индикаторы.
Например, rsi — фича1, atr — фича2, цена — фича3, объем — фича4 и т.п.
Все расчеты фич должны быть в таблицах данных, которые мы подаем для обучения.
Простыми словами, данные, которые нужны нейросети — это фичи и маркеры из первого этапа.
Полезный совет — всегда думайте, как нейросеть, чтобы было понятнее, какие фичи выбирать.
Я выбрал только относительные параметры, потому как считаю, что с абсолютными значениями цен и объемов нейросеть ничего не поймет, потому что цена и объем всегда уникальный и разный, в свою очередь, относительный всегда понятен своей относительностью.
Второй полезный совет: необходимо отдельно удостовериться, что фичи друг с другом не коррелируют, это добавит шум.
3 этап: создание алгоритма обучения, выбор параметров и типа модели, само обучение
В начале третьего этапа, а лучше с самого начала, позаботиться о железе, поскольку без хорошей видеокарты nvidia, поддерживающей cuda и т.п., модель будет учиться годами.
Далее необходимо определиться с типом модели; путем допроса различных LLM выявил единогласно тип модели LSTM, наиболее подходящей под рыночную структуру.
Для примера код обучения:
# LSTM-классификатор движения цены (3 класса)
# 0 - дно, 1 - ничего, 2 - вершина (в таблицах с маркировкой у меня это называется target)
import tensorflow as tf
import pandas as pd
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.mixed_precision import set_global_policy
from sklearn.preprocessing import StandardScaler
import glob, os
# ─── Основные гиперпараметры и пути ───────────────────────────────────────
"""
Здесь собраны все важные константы в одном месте — удобно настраивать эксперименты
"""
SEQ_LEN = 200 # сколько последних баров смотрим в прошлое при прогнозе и обучении
BATCH_SIZE = 256 # размер батча — баланс между скоростью и стабильностью
NUM_CLASSES = 3 # количество результатов предсказаний
FEATURES = [ # самые информативные признаки (по опыту)
перечисление всех ваших фич рассчитанных в таблицах. например относительный показатели цены, объемов, положения, структуры бара и т.п.
]
# Папки — меняйте под свою структуру
TRAIN_FOLDER = r"C:\data\train" папка для обучающих данных
VAL_FOLDER = r"C:\data\val" папка для валидационных данных
OUTPUT_DIR = r"C:\models\" папка для сохранения обученной модели
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ─── Загрузка и предобработка данных ────────────────────────────────────
"""
Важно: масштабирование обязательно для LSTM!
Без него градиенты будут взрываться или исчезать.
"""
train_files = glob.glob(os.path.join(TRAIN_FOLDER, "*.csv"))
val_files = glob.glob(os.path.join(VAL_FOLDER, "*.csv"))
print(f"Найдено файлов: train = {len(train_files)}, val = {len(val_files)}")
df_train = pd.concat([pd.read_csv(f) for f in train_files], ignore_index=True)
df_val = pd.concat([pd.read_csv(f) for f in val_files], ignore_index=True)
X_train = df_train[FEATURES].values.astype(np.float32)
y_train = df_train["target"].values.astype(np.int32)
X_val = df_val[FEATURES].values.astype(np.float32)
y_val = df_val["target"].values.astype(np.int32)
# Масштабируем по train-выборке (самый правильный и безопасный способ)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_val = scaler.transform(X_val)
# ─── Генератор последовательностей (tf.data) ────────────────────────────
"""
tf.data — самый быстрый и удобный способ подавать последовательности в модель
shuffle только на train — чтобы не перемешивать валидацию
"""
def make_dataset(X, y, shuffle=False):
def gen():
for i in range(len(X) - SEQ_LEN):
yield X[i:i+SEQ_LEN], y[i+SEQ_LEN-1] # последние 200 баров → метка следующего
ds = tf.data.Dataset.from_generator(
gen,
output_signature=(
tf.TensorSpec(shape=(SEQ_LEN, len(FEATURES)), dtype=tf.float32),
tf.TensorSpec(shape=(), dtype=tf.int32)
)
)
if shuffle:
ds = ds.shuffle(buffer_size=15000)
ds = ds.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)
return ds
train_ds = make_dataset(X_train, y_train, shuffle=True)
val_ds = make_dataset(X_val, y_val, shuffle=False)
# ─── Архитектура модели ─────────────────────────────────────────────────
"""
Три слоя LSTM — хороший компромисс между глубиной и скоростью обучения
return_sequences=True на первых двух — чтобы третий слой видел всю историю
Dropout после каждого LSTM — критически важен для финансовых данных (очень шумные)
"""
model = Sequential([
LSTM(256, return_sequences=True, input_shape=(SEQ_LEN, len(FEATURES))),
Dropout(0.35),
LSTM(192, return_sequences=True),
Dropout(0.30),
LSTM(128),
Dropout(0.25),
Dense(NUM_CLASSES, activation="softmax", dtype="float32") # выход всегда float32
])
model.compile(
optimizer=Adam(learning_rate=5e-5), # маленький lr → стабильность
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
model.summary()
# ─── Обучение с полезными коллбэками ────────────────────────────────────
"""
EarlyStopping → останавливаемся, когда улучшения нет
ModelCheckpoint → сохраняем лучшую модель по валидации
ReduceLROnPlateau → плавно снижаем learning rate при плато
"""
history = model.fit(
train_ds,
epochs=50,
validation_data=val_ds,
callbacks=[
tf.keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=6,
restore_best_weights=True,
min_delta=0.0002
),
tf.keras.callbacks.ModelCheckpoint(
filepath=os.path.join(OUTPUT_DIR, "lstm_best_epoch_{epoch:03d}_vl_{val_loss:.5f}.h5"),
monitor='val_loss',
save_best_only=True,
verbose=1
),
tf.keras.callbacks.ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=3,
min_lr=1e-7,
verbose=1
)
]
)
# ─── Финальное сохранение ──────────────────────────────
model.save(os.path.join(OUTPUT_DIR, "lstm_final.h5"))
print("Готовая модель сохранена ✓") Простыми словами, модель берет на вход все ваши фичи, а на выход выдает 3 класса, которые мы выше придумали, например, дно, вершина или ничего, обучаясь на окнах длиной в 200 баров и тренируясь на валидационной выборке.
4 этап: использование модели
По итогу предыдущих этапов у вас будет обученная модель.
Помните, я вначале писал, что нужно отсечь часть новых месяцев для тестирования, вот теперь на этих данных мы можем протестировать модель и увидеть, на сколько результат соответствует вашим ожиданиям и реальному положению дел.
В случае успеха переходим к 5 этапу, это создание технологии прогноза в реальном времени. То есть рыночные данные здесь и сейчас должны поступать в модель, а прогнозы пересылать вам.
Вердикт
С учетом, что все индикаторы технического анализа это производные от цен и объемов, то небольшого количества фич достаточно, чтобы натренировать модель, которая будет превосходить все индикаторы технического анализа, которых на рынке бесконечное множество, потому что все технические индикаторы строго механические, а нейросетевая модель это динамика, анализ контекста и учет всех факторов (если фичи хорошие).
Это даст вам статистическое преимущество, которое с помощью риск-менеджмента и дисциплины можно превратить в доход.
Повторюсь, от лица человека с немалым опытом торговли, отсутствие дисциплины это самое главное и самое тяжелое, что не дает преобладающему количеству трейдеров зарабатывать. Лудоманство — это сложно излечимая болезнь всех нас, без исключения.
