Постов с тегом "Машинное обучение": 783

Машинное обучение


Краткое описание методики прогнозирования

Я разработал нейросеть для анализа рынка. Она выбирает акции, обладающие низкой степенью риска и высоким потенциалом роста, с вероятностью более 80%.
Будет публиковаться часть выборки. Так же рассчитывается наилучшая цена покупки и предлагается уровень фиксации прибыли.
Через месяц так же будут публиковаться статистика точности прогнозов.

Кодирование свечей по Лиховидову

Кодирование свечей по Лиховидову.
Параметры большой, средний, маленький берутся по свечам того же времени предшествующих дней.
Может кому пригодится для ML.
А может ошибки найдете или улучшение предложите.

# -*- coding: utf-8 -*-
"""
Читает файл csv в DataFrame. Добавляет колонку с кодом свечи по Лиховидову.
Расчет (большой, средний, маленький) ведется по свечам тогоже времени за предшествующие дни.
Количество предшествующих дней выбирается. Нужно предусмотреть csv файл с большей историей чем start_date на day_delta
"""
import pandas as pd
import numpy as np
from pathlib import Path


class CandleCode:
    def __init__(self, start_date, day_delta, dir_source, file_source):
        self.start_date = start_date
        self.day_delta = day_delta
        self.df = pd.DataFrame()
        self.dir_source = dir_source
        self.file_source = file_source

    def csv_to_df(self):
        """
        Читает файл csv delimiter=';' в DataFrame
        :param dir_source: Папка откуда берем csv файл для обработки
        :param file_source: Исходный файл
        :return:
        """
        self.df = pd.read_csv(f'{self.dir_source}/{self.file_source}', delimiter=';')  # Загружаем файл в DF
        # Меняем индекс и делаем его типом datetime
        self.df = self.df.set_index(pd.to_datetime(self.df['date_time'], format='%Y-%m-%d %H:%M:%S'))
        # Удаляем колонку с датой и временем, т.к. дата и время у нас теперь в индексе
        self.df = self.df.drop('date_time', axis=1)

    def prev_df_to_dic_code(self, previous_df):
        """
        Из DataFrame предшествующего расчетной свече создает словарь с перцентилями для расчета
        (большой, средний, маленький) диапазон тела свечи и его теней.
        :param previous_df: Получает  аргументе DataFrame, с такимже временем свечей, предшествующий расчетной свече
        :return: Возвращяет словарь перцентилей 33% и 66%
        """
        percentile_dic = {}  # Создаем пустой словарь в который будем писать перцентили
        for index, row in previous_df.iterrows():  # Перебираем строки dataframe previous_df
            if row['open'] > row['close']:  # Свеча на понижение
                previous_df.loc[index, 'shadow_high'] = row['high'] - row['open']
                previous_df.loc[index, 'shadow_low'] = row['close'] - row['low']
                previous_df.loc[index, 'candle_body'] = row['open'] - row['close']
            else:  # Свеча на повышение
                previous_df.loc[index, 'shadow_high'] = row['high'] - row['close']
                previous_df.loc[index, 'shadow_low'] = row['open'] - row['low']
                previous_df.loc[index, 'candle_body'] = row['close'] - row['open']

        percentile_dic['shadow_high_33'] = np.percentile(previous_df['shadow_high'], 33)
        percentile_dic['shadow_high_66'] = np.percentile(previous_df['shadow_high'], 66)
        percentile_dic['shadow_low_33'] = np.percentile(previous_df['shadow_low'], 33)
        percentile_dic['shadow_low_66'] = np.percentile(previous_df['shadow_low'], 66)
        percentile_dic['candle_body_33'] = np.percentile(previous_df['candle_body'], 33)
        percentile_dic['candle_body_66'] = np.percentile(previous_df['candle_body'], 66)
        return percentile_dic

    def file_out(self, start, end, df_candle_code):
        """
        Функция записывает результирующий DF в csv файл
        :param start: Для имени выходного файла, начальная дата
        :param end: Для имени выходного файла, конечная дата
        :param df_candle_code: DataFrame который записываем в файл
        :return:
        """
        name_file_out = Path(f'{self.dir_source}/{self.file_source[:-4]}_{start}_{end}_lihovidov.csv')
        df_candle_code.to_csv(name_file_out)

    def run(self):
        df_candle_code = self.df.copy()  # Создаем копию DF, исключение предупреждений
        # Срез DF в котором будет дополнительная колонка с кодами свечей
        df_candle_code = df_candle_code.loc[self.start_date:]
        df_candle_code['candle_code'] = np.nan  # Создание дополнительного столбца и заполнение его NaN
        for index, row in df_candle_code.iterrows():  # Перебираем строки dataframe df_candle_code
            print()
            print(index)
            delta_day = pd.to_timedelta(f'{self.day_delta} days')  # Преобразование типа
            start_previous_df = index.date() - delta_day  # Вычисляем начальную дату DF
            end_previous_df = index.date() - pd.to_timedelta('1 days')  # Вычисляем конечную дату DF
            # Создаем DF предшествующий текущей строке
            previous_df = self.df.loc[start_previous_df.strftime("%Y-%m-%d"): end_previous_df.strftime("%Y-%m-%d")]
            previous_df = previous_df.loc[index.time()]  # Оставляем только строки соответствующие времени тек. строки

            percentile_dic = self.prev_df_to_dic_code(previous_df)  # Получаем словарь перцентилей

            code_str = ''  # Строка в которую будем собирать код для текущей свечи
            # Свеча на понижение (медвежья)
            if row['open'] > row['close']:  # Свеча на понижение (медвежья)
                code_str += '0'
                # Для тела медвежьей свечи
                if row['open'] - row['close'] > percentile_dic[
                    'candle_body_66']:  # 00 - медвежья свеча с телом больших размеров
                    code_str += '00'
                elif row['open'] - row['close'] > percentile_dic[
                    'candle_body_33']:  # 01 - медвежья свеча с телом средних размеров
                    code_str += '01'
                elif row['open'] - row['close'] > 0:  # 10 - медвежья свеча с телом небольших размеров
                    code_str += '10'
                # Для верхней тени медвежьей свечи
                if row['high'] - row['open'] > percentile_dic['shadow_high_66']:  # 11 - верхняя тень больших размеров
                    code_str += '11'
                elif row['high'] - row['open'] > percentile_dic['shadow_high_33']:  # 10 - верхняя тень средних размеров
                    code_str += '10'
                elif row['high'] - row['open'] > 0:  # 01 - верхняя тень небольших размеров
                    code_str += '01'
                else:  # 00 - верхняя тень отсутствует
                    code_str += '00'
                # Для нижней тени медвежьей свечи
                if row['close'] - row['low'] > percentile_dic['shadow_low_66']:  # 00 - нижняя тень больших размеров
                    code_str += '00'
                elif row['close'] - row['low'] > percentile_dic['shadow_low_33']:  # 01 - нижняя тень средних размеров
                    code_str += '01'
                elif row['close'] - row['low'] > 0:  # 10 - нижняя тень небольших размеров
                    code_str += '10'
                else:  # 11 - нижняя тень отсутствует
                    code_str += '11'

            # Свеча на повышение (бычья)
            elif row['open'] < row['close']:  # Свеча на повышение (бычья)
                code_str += '1'
                # Для тела бычьей свечи
                if row['close'] - row['open'] > percentile_dic[
                    'candle_body_66']:  # 11 - бычья свеча с телом больших размеров.
                    code_str += '11'
                elif row['close'] - row['open'] > percentile_dic[
                    'candle_body_33']:  # 10 - бычья свеча с телом средних размеров
                    code_str += '10'
                elif row['close'] - row['open'] > 0:  # 01 - бычья свеча с телом небольших размеров
                    code_str += '01'
                # Для верхней тени бычьей свечи
                if row['high'] - row['close'] > percentile_dic['shadow_high_66']:  # 11 - верхняя тень больших размеров
                    code_str += '11'
                elif row['high'] - row['close'] > percentile_dic[
                    'shadow_high_33']:  # 10 - верхняя тень средних размеров
                    code_str += '10'
                elif row['high'] - row['close'] > 0:  # 01 - верхняя тень небольших размеров
                    code_str += '01'
                else:  # 00 - верхняя тень отсутствует
                    code_str += '00'
                # Для нижней тени бычьей свечи
                if row['open'] - row['low'] > percentile_dic['shadow_low_66']:  # 00 - нижняя тень больших размеров
                    code_str += '00'
                elif row['open'] - row['low'] > percentile_dic['shadow_low_33']:  # 01 - нижняя тень средних размеров
                    code_str += '01'
                elif row['open'] - row['low'] > 0:  # 10 - нижняя тень небольших размеров
                    code_str += '10'
                else:  # 11 - нижняя тень отсутствует
                    code_str += '11'

            # Дожи
            else:  # Дожи
                if row['high'] - row['open'] > row['open'] - row['low']:  # Верхняя тень больше, медвежий дожи
                    code_str += '011'
                else:  # Верхняя тень меньше, бычий дожи
                    code_str += '100'
                    # Для верхней тени дожи
                if row['high'] - row['close'] > percentile_dic['shadow_high_66']:  # 11 - верхняя тень больших размеров
                    code_str += '11'
                elif row['high'] - row['close'] > percentile_dic[
                    'shadow_high_33']:  # 10 - верхняя тень средних размеров
                    code_str += '10'
                elif row['high'] - row['close'] > 0:  # 01 - верхняя тень небольших размеров
                    code_str += '01'
                else:  # 00 - верхняя тень отсутствует
                    code_str += '00'
                # Для нижней тени дожи
                if row['open'] - row['low'] > percentile_dic['shadow_low_66']:  # 00 - нижняя тень больших размеров
                    code_str += '00'
                elif row['open'] - row['low'] > percentile_dic['shadow_low_33']:  # 01 - нижняя тень средних размеров
                    code_str += '01'
                elif row['open'] - row['low'] > 0:  # 10 - нижняя тень небольших размеров
                    code_str += '10'
                else:  # 11 - нижняя тень отсутствует
                    code_str += '11'

            df_candle_code.loc[[index], ['candle_code']] = int(code_str, 2)
            print(int(code_str, 2))

        self.file_out(df_candle_code.index[0].date(), df_candle_code.index[-1].date(), df_candle_code)


if __name__ == '__main__':
    dir_source = 'c:/data_prepare_quote_csv'  # Папка откуда берем csv файл для обработки
    file_source = 'SPFB.RTS_5min.csv'  # Исходный файл
    start_date = '2020-09-01'  # С какой даты будем строить DF с кодами свечей
    day_delta = 365  # Дельта в днях для расчета показателей (большой, средний, маленький). Предшествует start_date

    code = CandleCode(start_date, day_delta, dir_source, file_source)
    code.csv_to_df()
    code.run()

Мои "значки на танчиках"

Лет 12 назад, когда я впервые ковырял тему нейросетей на фондовой бирже, прочитал как кто то облапошился обучая нейросеть распознавать танчики. Нет, сеть результат показала, но как оказалось на картинке с танчиками был какой то значок, а где танчиков не было, значка не было и нейросеть научилась распознавать не танчики, а наличие отсутствие вот этого значка. Запомнилось мне это наверно, потому что это было единственное, что я тогда понял о нейросетях. 
И вот теперь я поймал свои «значки», когда пытался предсказать динамику, на основе CNN+вейвлетпреобразований. Тут подробней. Нет я не заглядывал в будущее, и не так знак поставил где то. Я не стал нормализовывать цены, ибо считал что для CNN не важно все это, картинки они ведь и в Африке картинки, и вот так выглядит картинка вейвлетпробразования для ВТБ с ее копеечными ценами за акцию и Норникель, с его десятками тысячами рублей за акцию:
Мои "значки на танчиках"

( Читать дальше )

CNN+wavelet

Займемся бессмыслицей. Никакого прогнозирования, просто попробуем методами вейвлет преобразований и CNN ответить на вопрос — есть или нет разница в цикличности при росте фишки и падении? Эллиот чертил 3 волны вверх и 2 вниз. Давайте почертим и мы.
Данные я взял недельные, от понедельника до пятницы, но с разбивкой по 15 минуткам, итого ряд в 175 элементов. Судя по прошлым результатам, мизерная длина, и никакой цикличности там нет. Но...«а вдруг?!». Ну а разбивка недельная, в надежде уловить недельную цикличность, все таки понедельник это «день тяжелый», пятница это «тяпницы», четверг это маленькая пятница. В общем каждый день недели уникален и помню какие то корреляции/антикорреляции даже были, вроде пятница и понедельник шли вразрез, а четверг и пятница шли вместе. Впрочем точно не помню.
Каждому ряду в 175 отчетов я присвоил лейбл (1 рост, 0 падение). Ряд прогнал через вейлет преобразование, получив квадратную картинку. Все это добро загнал в CNN и стал ждать чего нейросеть намутит. В теории, после вейвлет преобразования, на полученной картинке, не должно быть никакого намека на то росла фишка или нет. Следы наличия тренда присутствуют, но какого именно не указывается. Хотя это не точно. А вот точно что должны быть следы цикличности, и если при росте и падении цикличность разная то точность классификации должна быть больше 0,5… Хотя это не точно.  Ну нам жалко чтоли, попробовать? Пуская нейросетка крутит колесико. Крутило колесико нейросеть долго....:

CNN+wavelet



( Читать дальше )

Трейдинг и машинное обучение (svm)


Недавно посоветовали прочитать статью про применение SVM к торговле акциями. Если перевести дословно название статьи: SVM подход к торговле акциями. SVM это support vector machine один из алгоритмов обучения, на русском звучит как метод опорных векторов. Далее краткий пересказ статьи и в конце мои мысли по ней.

Что они сделали. Взяли часть акций из SP500, которые относятся к нефти. Определили параметры, у которых есть связь с ценой (в порядке значимости):

— Historical Price
— Trading Volume
— Historical Oil Prices
— P/E Ratio
— Enterprise Value / EBITDA
— Current Assets / Current Liabilities
— Total Assets / Total Liabilities
— Percentage of Analysts Recommending Buy and Sell
— Investing Cash Flow / Depreciation
— Market Capitalization / Operating Cash Flow
— Market Capitalization / Revenue
— Operating Cash Flow / Revenue
— Net Increase (Decrease) Cash / Revenue

У них были дневные данные с января 2001 по ноябрь 2009 года (статья 2009 года). Брали данные за 5 дней и пытались предсказать, что будет в следующий день. Первые 6 лет взяли для тренировки алгоритма и последующие 3 года для теста.

Для каждой акции брали разное количество параметров: 1, 5 и 14.

( Читать дальше )

Еще о торговле по частотам

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

Еще о торговле по частотам
Опять уже привычный период в 220 (годовая периодичность), который тянется до 2500 отчета. Ну если быть точней он меняется, начал с 220, потом опустился ниже, затем вернулся обратно, но мы люди не гордые, упростим ситуацию, будем считать период константой.
Опять накладываем гармонику с годовым циклом и получаем что то вроде:

Еще о торговле по частотам

( Читать дальше )

Частоты на фондовой бирже. Часть1.

Как можно представить разложение Фурье и Вейвлеты? Не вдаваясь в математику, в которой я прямо скажем не большой специалист, это представление временного ряда в других системах координат. 

Вот например такой ряд — немножко похожий на котировку застрявшей в боковике акции.
Частоты на фондовой бирже. Часть1.

Опытный трейдерский глаз конечно сразу заметит что на котировку это не очень похоже. Но я сейчас не об этом, я о том что этот внешне беспорядочный ряд раскладывается на 4 гармоники (плюс розоватый в самом низу-шум). 
Частоты на фондовой бирже. Часть1.

( Читать дальше )

О тех индикаторах с точки зрения нейросетей.

Что если в качестве лейблов на выход подавать не рост/падение рынка завтра, а срабатывание каких то техиндикаторов? Есть несколько классических правил торговли. Ну например пробой снизу вверх Close BolingerUpperband это к покупке, и сверху вниз BolingerDownperband к шорту. Или дивергенция MACD. Или Close пробивает SMA. Ну а че вы смеетесь? Когда я работал в представительстве Финама, мы предлагали клиентам следовать корпоративной стратегии, а вся стратегия это пробои Болинджеров. Я, как человек который вообще тогда не понимал как это все делается, готовился услышать какую то хитрую систему для зарабатывания денег, от московских экспертов, а когда услышал «тайну», я такой «эээээ....». Или вот дивергенция MACD, открываешь википедию и там прямо «это сильнейший технический индикатор, если дивергенция то вот прям точно точно!». 
Месяц назад я пробовал подать на вход CNN+GramianAngular падение/рост рынка,  без каких то видимых успехов. Может тут проблема в инструменте?  Попробуем спрогнозировать с помощью нейросети срабатывание этих самых техиндикаторов, подав цены накануне. Причем усложним задачу, будем подавать не точное число баров, а фиксированное, скажем 30. То есть нейросетка получает избыточные данные: мы хотим предсказать пересечение Close c SMA(25) а мы ей 30 баров предлагаем. 

( Читать дальше )

ВТБ и холодный август двадцатого

    • 14 сентября 2020, 09:55
    • |
    • ruru42
  • Еще
Кофе, солнце, ветер и свежесть августа. Обещание осени и вялая городская суета позднего утра. Иду в ВТБ. Есть брокерский счет. Есть привязанная карта. Хочется чего-то зеленого. Захожу снимать доллары. 

В отделении ВТБ только в это нежное время относительно немного клиентов. Беру талон. Немного жду. Прохожу в кассу.

— У вас лимиты, вам нельзя столько долларов сегодня.
— Я уже делал заказ на снятие, заказ не пришел. Сколько можно снять сегодня?
— До ХХХХХХ руб в эквиваленте. 
— Хорошо, давайте.
— У вас карточка не проводится, обратитесь к менеджеру.

.....

Чуть позже, на рецепшене. 

— Возьмите талон на менеджера.
(Беру, жду, подходит очередь)

— Хочу снять деньги, с карточки не выходит. 
— Хорошо (нажимает кнопки)… — Странно, все должно работать. Ну ничего, сейчас ордером оформим. Какая сумма? 
— ХХХХХХ. 
— Можно ваш паспорт? Сейчас прийдет смс, назовите код. (Смс не приходит, что-то не работает). — Сейчас, нужно подождать программа подзависла. (Еще ждем).

( Читать дальше )
  • обсудить на форуме:
  • ВТБ

Архитектура, при которой стратегия упаковывается в файл. Algo-only.

Придумал интересный подход. Мож кого натолкнет на интересные идеи какие-то.

 

Сейчас начал торговать ML модели. С практической стороны с моделями какая сложность – там есть процесс предобработки данных – генерация признаков в основном (если с точки зрения трейдинговых данных заходить), поэтому нельзя просто сохранить модель, в другом месте загрузить и она будет работать, надо сохранить, загрузить, предобработать исходные данные к тому виду, к которому приучена модель и только тогда она будет работать. К счастью тонна сопутствующих трудозатрат убирается такой классной штукой как пайплайн – сейчас моя модель это 2 пайплайна – один для предобработки данных, другой для предикта (сама модель). Т.е. я где-то что-то рисечу, дальше автоматика упаковывает в пайплайны (2 на модель, как сказал). Все, могу кинуть эти 2 файла в папку с моделями, откуда их забирает торгующий блок и, собственно, отторговывает. Красота. Всякие мета-данные – тикер там, время удержания позиции и прочие мета-логики упаковываю или в сам пайплайн или в название файла. Красота.



( Читать дальше )

....все тэги
UPDONW
Новый дизайн