Блог им. karat39

Как я учу нейронки. Моя первая нейронка. Подготовка кода и данных

Начало было положено тут

Привет смартлаб. Свою «карьеру» на СЛ, как и собственно карьеру в трейдинге я начал с цикла статей, как я «готовил» протокол FIX для валютного рынка. К слову сказать, тогда еще молодой провинциал никому не был нужен в столицах, я был прижат к стене и просто начал писать, как я готовлюсь к работе. Это сыграло сильнейшую роль в моем будущем. 

Сейчас я не преследую никаких целей. Хотя… Тут не стоит зарекаться. Как сказал однажды коллега: «Ты конечно молодец, создал себе на СЛ портфолио и теперь оно играет на тебя». Ну да, что есть, то есть. Но на текущий момент, мне просто интересно рассказывать, как я иду по этим ступенькам. Слушать и прислушиваться к вашим комментам. Так что вы тут можете мене ругать, отрицать и отговаривать, как в предыдущем топике )

Собственно почему? Ну знаете, это профессиональная чуйка. Я стал видеть в них будущее. Это знаете, как примерно в 2017 почувствовался вкус денег в стратегиях и пришла такая же чуйка, что нужно срочно переквалифицироваться на fpga разработчика и начинать развивать эту тему в стратах. Чего уж там скрывать, это тогда сыграло решающую роль и с тех пор, скорее всего, я могу назвать себя уже неплохим спецом в этой тематике.

Вот также и сейчасc. Я полный ноль и чувствую молодежь начнет съедать меня, если не начну сейчас посвящать этой теме хотя бы 1-2 часа в двое суток.

Такс. Приступим

Спасибо вам всем за отклики в предыдущем топике. Ряд их мне очень помог. Что я понял? Что мне нужен какой то десептикон персептрон. И я начал рыть.
Стало понятно, что все нейронки делятся на 3-4 типа решаемых задач. И моя задача, которая нужная чисто для изучения нейронок, относится к разряду классификации (ну например классифицировать тот или иной паттерн). А чтобы ее решить, нужен мне хотя бы однослойный персептрон.

Я много прочитал про нейронки. Про эти персептроны. И что я решил для себя? Пусть она для меня по прежнему остается черным ящиком пока. Я уверен, как всегда, все придет само, когда я буду к этому готов. Ну а пока, я запомню, что это будет черный ящик, на вход которого я подам какие то данные, от них возьмется какая то функция (я даже знаю какая), а от этой функции возьмется еще одна функция (типа выход), чтобы узнать конечный результат. Это все, что пока мне надо.

Далее, я тупо, по совету из прошлой темы, обратился к chatgpt, позадавал ей вопросы, которые не мог найти (типа «сколько надо делать слоев», «сколько надо делать нейронов») и тупо закончил это исследование «пример на питоне однослойного персептрона», «пример обучения на питоне однослойного персептрона»

Ну хорошо, на этом и порешаем, моя первая нейроночка будет выглядеть так:
class Perceptron:
    def __init__ (self, _input_cnt):
        self.weights = np.zeros (_input_cnt)
        self.bias = 0

    def predict (self, _inputs):
        z = np.dot (_inputs, self.weights) + self.bias                  # сумматорная функция
        return  np.where (z > 0, 1, 0)                                  # пороговая функция активации

    def train (self, _inputs, _targets, _learning_rate = 0.1, _epochs = 100):
        for epoch in range (_epochs):
            for input, target in zip (_inputs, _targets):
                prediction      = self.predict (input)
                error           = target - prediction                   # ошибка предсказания
                self.weights    += _learning_rate * error * input       # корректировка весов
                self.bias       += _learning_rate * error               # корректировка смещения

Теперь данные

По мере того, как я все больше читал и изучал, я понял, что изначально задачу я поставил не правильно. Мне не нужно прогонять какой паттерн на истории, мне на истории нужно выявить паттерн. Хотя бы чисто ради интереса.

Для этого я поставил задачу: выявить три свечи, где хай третьей больше первых двух и где последующие хаи пяти свечей буду всегда ниже это третье. Банально, я хотел выявить нечто похожее, правда сильно ошибался:

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

Сами свечи я решил дернуть по привычке по iss, ну а потом подгружать их из файла, чтобы не часто дергать сервер moex:
class Data:
    def __init__ (self, _sec_code):
        self.sec_code   = _sec_code
        self.df         = []

    def get_cndls_moex (self):
        with requests.Session() as session:
            data             = apimoex.get_market_candles (session, security = self.sec_code, interval=10, start=DATE_START, end=DATE_END, market='shares', engine='stock')
            self.df          = pd.DataFrame (data)
            self.df['begin'] = pd.to_datetime (self.df ['begin'])

            self.df.rename (columns = {'begin':'dtm'}, inplace = True)

    def get_cndls_csv (self, _file_name):
        self.df = pd.read_csv (_file_name, sep = '\t')

    def save (self, _file_name):
        self.df.to_csv (_file_name, sep = '\t', index = False)

Приведение данных

Что я решил подавать на вход этого черного ящика? Первые три свечи, типа паттерн. Ну так, чисто для обучения. Эти свечи нужно как то характеризовать, для этого я пока выбрал такие характеристики:
  • размер тела
  • размер верхнего хвоста
  • размер нижнего хвоста
  • полный размер свечи (хай — лоу)
при этом понятно, что эти величины нужно считать как относительные, я не прямые величины в пунктах (цены то везде разные) То есть относительно чего то, например отношение тела к размеру всей свечи или отношение нижнего хвоста к размеру всей свечи. Банально, если приглядеться, я распили свечь на три части: два хвоста и тело и высчитал их процентное отношение ко всему размеру.

Далее, инструменты у нас разные, ну или инструмент один, а рынок разный. И здесь нужно вводить относительностью. Рынок у нас обычно чем характеризируется? Ну вроде ликвидность и волатильность. Поэтому я решил привязаться к волатильности и ввести еще один показатель свечи, так как: отношение размера свечи к ATR, то есть
((high — low) / atr). Это чтобы наша нейроночка не сильно привязывалась к инструменту.

В питоне это выглядит примерно так:
#подсчет хвостов
    def calc_tails (self):
        self.df.loc [(self.df.close >= self.df.open),"range_h"] = self.df ['high'] - self.df ['close']
        self.df.loc [(self.df.close < self.df.open),"range_h"]  = self.df ['high'] - self.df ['open']

        self.df.loc [(self.df.close >= self.df.open),"range_l"] = self.df ['open']  - self.df ['low']
        self.df.loc [(self.df.close < self.df.open),"range_l"]  = self.df ['close'] - self.df ['low']

    #подсчет тела
    def calc_range (self):
        self.df ['range']   = self.df ['high']  - self.df ['low']
        self.df ['range_b'] = self.df ['close'] - self.df ['open']

    def calc_atr (self):
        df_tr           = pd.DataFrame([self.df ['high'] - self.df ['low'], abs (self.df ['high'] - self.df ['close'].shift()), abs (self.df ['low'] - self.df ['close'].shift())]).T.max (axis=1)
        self.df ['atr'] = df_tr.rolling (window = 14).mean ().round (3)

    #подсчет характеристик свечей
    def calc_cndls_desc (self):
        self.df ['desc_range']  = (self.df ['range'] / self.df ['atr']).round (2)
        self.df ['desc_b']      = (self.df ['range_b'] / self.df ['range']).abs().round (2)
        self.df ['desc_h']      = (self.df ['range_h'] / self.df ['range']).round (2)
        self.df ['desc_l']      = (self.df ['range_l'] / self.df ['range']).round (2)
        self.df ['desc_direct'] = 0
        self.df.loc [(self.df.range_b >= 0),"desc_direct"]  = 1
Как я учу нейронки. Моя первая нейронка. Подготовка кода и данных

Ну и осталось разметить результат, для этого я ввел два признака:

  • tag_1 — когда хаи последующих пяти свечей ниже текущей
  • tag_2 — когда хаи предыдущих двух свечей ниже текущей
Питон конечно круто со своим пандасом работает как sql:
 
def set_tag_1 (self):
    self.df ['tag_1'] = 0
    self.df.loc [
        (
            (self.df['high'].diff (-1) > 0) & 
            (self.df['high'].diff (-2) > 0) &
            (self.df['high'].diff (-3) > 0) &
            (self.df['high'].diff (-4) > 0) &
            (self.df['high'].diff (-5) > 0)
        ),
    "tag_1"]  = 1

def set_tag_2 (self):
    self.df ['tag_2'] = 0
    self.df.loc [
        (
            (self.df['high'].diff (1) > 0) & 
            (self.df['high'].diff (2) > 0)
        ),
    "tag_2"]  = 1


Получаем, когда tag_1 и tag_2 равны 1, это получается примерно тот паттерн, который будет перебираться на истории.

Мой первый FAIL

Вообще, что меня сразу начало тревожить, я думал, что если я задам такие характеристики свечей, я тупо не найду на истории хотя бы одну точно такую же свечь.
Но глянув стату с помощью:
def group (self):
        gr_df = pd.DataFrame (self.df [['desc_b', 'desc_h', 'desc_l']])
        gr_df = gr_df.groupby(['desc_b', 'desc_h', 'desc_l']).size ()
        print (gr_df)
я быстро отмел эти сомнения, похожих свечей полно. Будут ли похожие паттерны? Ну посмотрим. На этот счет у меня будет запасной вариант, ну например, для характеристик свечей вводить допуск. То есть тело не 20%, а диапазон 20-30%. Вообщем практика покажет. Как видите я пишу прям online и будущего не знаю.

Но настоящий fail я получил, когда начал автоматически сохранять эти участки графика, чтобы просто глянуть, что там. Кстати питон все так же крут и делает это предельно легко:
def draw_targets_cndl (self, _targets):
        clr_down= 'red'
        clr_up  = 'green'
        width   = .3
        width2  = .03

        for i in range (10):
            idx     = _targets.iloc [i:i+1].index.values[0]
            df      = pd.DataFrame (self.df.iloc [idx - 2 : idx + 6])
            print ()
            print (df)
            up      = df [df.close >= df.open]
            down    = df [df.close <  df.open]

            plt.figure()
            plt.bar (up.index, up.close-up.open, width, bottom = up.open, color = clr_up)
            plt.bar (up.index, up.high-up.close, width2, bottom = up.close, color = clr_up)
            plt.bar (up.index, up.low-up.open, width2, bottom = up.open, color = clr_up)
            plt.bar (down.index, down.close-down.open, width, bottom = down.open, color = clr_down)
            plt.bar (down.index, down.high-down.open, width2, bottom = down.open, color = clr_down)
            plt.bar (down.index, down.low-down.close, width2, bottom = down.close, color = clr_down)
            plt.xticks (rotation = 30, ha = 'right')
            plt.savefig("img/targets/" + str (i) + ".png")

И первая картинка мне прям зашла:
Как я учу нейронки. Моя первая нейронка. Подготовка кода и данных

Но когда я стал перебирать далее, это просто FAIL. Давайте поржем вместе:

Как я учу нейронки. Моя первая нейронка. Подготовка кода и данных
Кстати по началу я думал, что хаи третьей свечи тупо перебивают остальные, но тут какой то баг. Буду разбираться.
Не скрою, что есть прямо крутые картинки, но чего их смотреть, победителей на СЛ и так хватает.

Вообщем пока нравится мне эта задача своей простотой. Как видите, я еще не начинал обучение, о котором буду писать далее )
Всем удачи)



 

Данная публикация является личным мнением автора. Мнение владельца сайта может не совпадать с мнением автора.
5.3К | ★16
54 комментария
Смартлабовский карьерист)
Халявщик, ага )) со стажем
avatar

Интересно будет посмотреть, как минимум с какого-то этапа обучения), да и так уже любопытно.

 

Я бы только нейросети сразу писал, даже если простейшая архитектура (читай однослойный перцептрон), на каком-нибудь фреймворке, не знаю, какой поинтуитивней — keras, наверно. В ML всё на библиотеках, видишь как ты сдружился с pandas, нейросеть на голом питоне это примерно как таблицы голым питоном, а не пандасом обрабатывать). Ну эт так, для следующих шагов, когда поймёшь, что с однослойным перцептроном каши не сваришь)).

avatar
Replikant_mih, тут такая штука. Возможно, когда нибудь, придется перекладывать все в физическое железо, поэтому фреймворки пока не подходят. Посмотрим
avatar
Андрей К, пока, в смысле результата, эта постановка задачи — пустая трата времени.
Возможно, когда нибудь, придется перекладывать все в физическое железо, поэтому фреймворки пока не подходят. Посмотрим
Для перекладки подобных задач в железо уже есть готовые решения. Сама НС и ее обучения занимают несколько строк кода. Скажем, Raspberry PI вас устроит?
Удачи.
avatar
3Qu, не, хотелось бы все на кончиках пальцев на уровне наносек в идеале через 1-2 года ). Любое процессорное решение не подходит
avatar
Андрей К, с тем же успехом и без заморочек можно и на видеокарту.
Наносекунды для МОЕХ бессмысленны.
avatar
3Qu, 
Наносекунды для МОЕХ бессмысленны.
последние 7 лет мыслю только на уровне наносек. Увы, по другому не научился. Так что работаем то, что имеем
avatar
Андрей К, задержки по любому составляют до 1-2 с, и ваши нс уже ничего не решают.
avatar
3Qu, комон, даже как то обидно ) Мои все издержки равны сетевым + задержки ядра биржи, а это 80+20 = 100мксек. Как то так. Тиктутред в таких масштабах можно пренебречь, он там меньше 1мксек
avatar
Андрей К, )) Пинг уже 10мс.
avatar
3Qu, специально щас посмотрел. Пинг у меня или любого моего коллеги до коммутатора, который стоит перед срочкой приблизительно 0.8млс, что естесно не говорит о реальных сетевых задержках. Лоу летенси пингами не меряются
avatar
Андрей К, ну, если у вас какой-то другой инет, то наверное.
У меня обычный и еще сервер брокера до биржи. Плюс еще тормозной Квик.
Тем не менее, у меня не ХФТ, и я не вижу для себя ухудшений работы от задержек в 1-2 с. Плюс копейки неинтересно.
avatar
3Qu, с задержками 1-2с даже не воспользоваться нормально Book-or-Cancel, а это вовсе не про HFT. Тормозной QUIK и тормозной Lua вполне укладываются в 100мс, если действовать разумно.

P.S. для С++ программера самая большая сложность в Lua — в процессе писания кода абстрагироваться от того, насколько там все через жопу выполняется. Иначе грустные мысли и нервный тик в виде вредных микрооптимизаций :)
Кирилл Гудков, собственно, через задницу в Луа только события, работающие в основном потоке терминала. Никуда не денешься, просто писать события короче.
Да и всю ТС писать на Луа моветон.
avatar
3Qu, 
в смысле результата, эта постановка задачи — пустая трата времени.
ну увы, у меня нет других примеров, так как не владею предметной областью )
это как, когда впервые сел изучать программирование GUI, типа Delphi и первая задача для примера hello world у всех на ум приходит калькулятор )
avatar
Не очень понятно зачем здесь ML. Для выявления закономерностей не проще ли пойти путем кластеризации. Банальной K-Mean или более сложной GMM.
avatar
nicknh, K-Mean так то тоже ML)
mirumir, Вот авторы в 1950-х удивились бы. Помню в 90-х метод Монте-Карло так и назывался. Теперь куда не глянь везде ML. Хотя приглядевшись, все забытое старое в новой интерпретации.
avatar
nicknh, А что удивляться то. Может в 50 и удивились бы не знаю,  но сейчас алгоритм изучают как базовый алгоритм МЛ. А кластеризация одна как раз одна из основных задач МЛя. Может Вы путаете с МЛ и нейронные сети? МЛ то общее понятие, туда много тем входит. 
mirumir, Согласен. Везде где есть какая-то модель, и она от данных меняется, считай обучается — всё это ML, в т.ч. перечисленные вещи.
avatar
mirumir, а quicksort в соответствии с новыми тенденциями в ML еще не определили? :)
nicknh, по чесноку я ничего не понял )) так что будем ждать, пока я наработаю компетенции
avatar
Кстати, послушать, в каких конкретных вопросах и типах вопросов, затыках и как конкретно ChatGPT-like вещи используешь — было бы тоже очень любопытно услышать.

avatar
В части поиска паттернов — это прям Алексей Ван образца 2014 года. С его программой для этого. Как я понял, вывод у него образовался неутешительный — паттерны выигрыша не дают.
avatar
svgr, ну было бы странно, если б давали ). Точнее, давали предсказуемо и на долгий срок. Ну Вы сами подумайте, на одном и том же активе работают даже не десяток, а сотни, тысячи роботов. У всех разные алгоритмы. Как Вы угадаете результат их движений? )
Вася Пражкин, так и я бы уточнил. Копать надо тоньше, чем просто перебирать доступные всем свечи.
И тогда как раз результаты движений и проступают. Например, можно взять всеми любимые «уровни» и посчитать как глубоко от них стопосъём делают прежде чем пойти куда все ждут. А делают это по алгоритмам и объёмами, редко допускающими возражения.)
avatar
svgr, как глубоко от них стопосъём делают
А Вам не приходит в голову, что глубина стопосъема может быть не постоянной?
Вася Пражкин, ста — тис — ти — ка.
avatar
svgr, Вы сможете статистически посчитать стопосъемы у Deep Learning моделей?
svgr, ага, следил за ним тогда. Мне было сложно тогда понять как формализовать паттерны.
В целом сейчас эта задача, чтобы просто наработать опыт и компетенции, не более. Типа хэллоу ворлд
avatar
Андрей К, я не думаю, что ваши поиски не будут иметь практического значения для торговли. Методов 'оцифровки в какие-то однородные элементы' текущих цен можно придумать много. Соответственно, результат статистики на них лучше белого шума тоже получить можно. Вопрос насколько лучше (надо же перекрыть комиссии). Какая-то идея, хоть как-то отражающая реальное движение цен, в основе кластеризации графика цен даст преимущество. Придумывать — программировать — проверять.
avatar
svgr, 
у Лехивана ничего выигрыша не дает, кроме инфоцыганства
А почему не определять паттерн обычным алгоритмом, у вас же есть критерии. Не очень понятно
avatar
in_line, фишка в том, что Паттерна у меня нет. Вроде примерно об этом написал
avatar
Андрей К, а что мешает собрать статистику голова_паттерна->популяция(варианты_хвостов), навыбирать хорошо предсказывающих голов? Задача вроде детерминистическая, оптимизированная реализация позволит перебирать довольно длинные головы. По алгоритмам можно копать в сторону обработки длинных строк. И никакого подбрасывания костей ML не нужно.
Не совсем ясно зачем с нуля писать сеть, вместо использования TF иди PyTorch, но для обучения и понимания это точно полезно. 
mirumir, ответил чуть выше. Пока что, готовое мне не подходит
avatar
Андрей К, неправильно понимаете. Обучать сетку сложно и муторно и ресурсов требует. Лучше пользоваться либами.

А уже обученную можно вывести хоть в виде чистого C кода и куда угодно можно будет прошить.
avatar
Alex, поддерживаю. Думаю, что наиболее рациональное решение — это обучить модель на хорошей библиотеке, а уже саму обученную модель прошить в железо.
Алексей Манин, ну хорошо. Тогда у меня вопрос. Почему я это не смогу сделать на текущем решении?
avatar
Андрей К, сможете. Только на мой взгляд — это не оптимальное решение.
tag_1 и tag_1 — это просто условие локального 2-5 максимума. Такое встречается и в трендах вверх, и в трендах вниз, и в боковиках, и в шуме… Вы уверены, что хотели научить сеть находить именно это?
avatar
Errar, ну как отправная точка, ага. А там как кривая мысли выведет 
avatar
Лучше применять нейронки не к ценам, а к людям. Гораздо больше соотношение сигнал/шум. И быть не алготрейдером, а инфоцыганом)
avatar
О! наконец возвращение к полезнейшим постам!
Спасибо. Слежу за прогрессом.
avatar
Eldar Shaymardanov, спасибо )
avatar
Согласен, теперь продолжите исследования и сосчитайте МО((H+L)/2 следующей свечи - (H+L)/2 текущей свечи) для какого-либо ряда свечей.
То есть размеры приращений * эти вероятности.
Результат очевиден — тот же, что и для «купил и держи».
avatar
А цель-то какая? Трейдинг, или так, развлечься?
avatar
bascomo, развлечься
avatar
Андрей К, хорошее дело.

Рекомендую попробовать подход, когда нейросеть предсказывает сигнал на вход. Покупать, ничего не делать, продавать.
1
0
-1
Активация сигмой

Фреймворки керас, тензорфлоу

Сети примитивные, как перевёрнутая пирамида Маслоу.
Решается задача классификации.

Выбросить идеи, что на вход нужно подавать свечи или другие ценовые данные.

На вход подавать сигналы: 1 или 0 (есть сигнал или нет сигнала).
Сигнал — это паттерн или индикатор.
Примеры сигналов:
  — три восходящие свечи (close выше close)
  — три нисходящие свечи (close ниже close)
  — пересечение скользящих
  — зоны перепроданности/перекупленности осцилляторов RSI и подобных
— пересечение кривых Stochastic в зонах перепроданности перекупленности

Нейросеть сама отсечёт левые сигналы
Чем больше сигналов подать на вход, тем лучше.
У меня результаты были до 90% точности по предсказаниям 2 из 3 классов — когда покупать, когда продавать.

Основная проблема — балансировка сети между классами.
avatar
Никогда не верил в  нейросети, потому что плохо тестируемы, т.е. практичнее букву Г на графике распознавать или что-то такое, что можно проверить визуально.
avatar

Читайте на SMART-LAB:
Фото
Новые возможности с БКС API: торги заблокированными активами, внебиржевой валютой и другое
Делимся новостями БКС API¹ — мы выпустили три важных обновления, которые расширяют торговые инструменты и упрощают работу с рыночными...
Обновление кредитных рейтингов в ВДО и розничных облигациях (ООО "Лизинг-Трейд" понижен ruBB+, ООО «Оил Ресурс» и АО «Кириллица» отозван)
🔴ООО «Лизинг-Трейд» Эксперт РА понизил рейтинг кредитоспособности до уровня ruBB+ и изменил прогноз на развивающийся. Ранее у Компании...
Фото
Токио против рынка: сколько резервов хватит для защиты иены
Цены на нефть продолжают снижение, начавшееся в среду, хотя темпы падения уже замедлились. За последние сутки новостной фон по Ближнему Востоку...
Фото
ЦИАН. Отчет МСФО Q1 26г. Такой рентабельности никогда не было
Вышли финансовые результаты по МСФО за Q1 2026г. от компании ЦИАН: 👉Выручка — 3,90 млрд руб. (+17,9% г/г) 👉Операционные расходы — 2,72...

теги блога Андрей К

....все тэги



UPDONW
Новый дизайн