Блог им. 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. Давайте поржем вместе:

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

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



 

★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

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

....все тэги



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