Logo

Вход

Войти с помощью соц. сетей
Пока нет объявлений.
X
 
  • Фильтр
  • Время
  • Показать
Очистить всё
новые сообщения
  • #1 Свернуть

    Python и анализ данных

    Навеяно данной темой. Поскольку там нет никакой активности, то попробую обрисовать свое видение данной проблемы.
    Почему собственно python? Python - это кроссплатформенный, интерпретируемый язык программирования общего назначения с динамической типизацией. Python обладает богатой стандартной библиотекой и обширной экосистемой пакетов. Сегодня можно выделить три основных ниши, где применяется python:
    1. скрипты для администрирования операционных систем
    2. программирование для web (фреймворки Flask и Django)
    3. анализ данных и машинное обучение

    Нас собственно будет интересовать последний пункт. В этой теме я постараюсь описать как использовать python для загрузки, обработки и визуализации данных. Немного затрону тему машинного обучения. Возможно - глубокое обучение на python (нейросети) и байесовскую статистику.
    Для работы нам понадобится интерпретатор python и некоторый библиотеки:
    • numpy
    • scipy
    • pandas
    • matplotlib
    • scikit-learn
    • tensorflow
    • pymc3
    • statsmodels

    Если лень возиться с установкой библиотек, то можно взять специализированный дистрибутив anaconda.
    Теперь кратко о библиотеках:
    numpy - отвечает за высоко оптимизированные многомерные массивы (основная структура данных для большинства современных алгоритмов)
    scipy - реализует на базе массивов numpy быстрые числовые алгоритмы
    pandas - более высокоуровневая надстройка над numpy (включает в себя структуры данных с помеченными осями, функциональность для работы с временными рядами и пр.)
    matplotlib - библиотека для построения графиков
    scikit-learn - библиотека машинного обучения
    tensorflow - библиотека глубокого обучения от компании Google
    pymc3 - байесовская статистика
    statsmodels - библиотека для проведения статистических тестов и оценки статистических моделей

    С введением вроде все. В следующей статье начнем работу.
    Do not go where the path may lead, go instead where there is no path and leave a trail.
    Ralph Waldo Emerson
  • <a href="https://www.instaforex.org/ru/?x=ruforum">InstaForex</a>
  • #2 Свернуть

    Сначала небольшое отступление. В качестве среды разработки будет использоваться Jupyter. Кому интересно могут почитать более подробную информацию на официальном сайте.
    А теперь первый наглядный пример. При анализе данных, нам эти данные нужно откуда-то получить. В качестве примера я возьму дневные данные по EURURSD с сайта Dukascopy в формате csv.

    Нажмите на изображение для увеличения.

Название:	1.png
Просмотров:	1
Размер:	27.1 Кб
ID:	28091011

    Первая строка - обычный импорт библиотек
    Вторая строка нам особо не интересна. Она задает размер для графиков.
    Третья строка - самая интересная. В ней мы загружаем наш csv файл. На самом деле pandas умеет загружать данные разных форматов: csv, json, html, ms exel, hdf5 и даже SQL. Более подробную информацию смотрите на pandas io tools.
    При загрузке данных мы указали, что хотим преобразовать временные метки из нашего файла в объект datetime. Так же мы задали в качестве оси индексирования наши временные метки. Оси индексирования - это одна из главных "плюшек" библиотеки pandas. С помощью осей мы можем производить слияние нескольких DataFrame объектов, выбирать подмножества, сдвигать данные, производить передискретизацию и многое другое.
    После загрузки данных мы получаем объект DataFrame. Он представляет собой табличную структуру данных. В самом простом варианте - двумерную. Но за счет иерархического индексирования DataFrame может быть и многомерным.

    Нажмите на изображение для увеличения.

Название:	2.png
Просмотров:	1
Размер:	28.4 Кб
ID:	28091012

    После загрузки мы можем посмотреть на наш объект. Он содержит метод head, который возвращает первые N строк нашего датафрейма. По умолчанию - 5, но можно указать любое число в качестве аргумента.

    Ну и наконец мы можем визуализировать наши данные. Построим график по ценам закрытия и в качестве бонуса навесим экспоненциальное скользящее среднее за 60 дней.

    Нажмите на изображение для увеличения.

Название:	3.png
Просмотров:	1
Размер:	77.8 Кб
ID:	28091013

    Вот так мы смогли загрузить и визуализировать наши данные за минимальное количество строк кода.
    На сегодня все. Весь код доступен на
    g i t h u b.com/extlife/data_analysis
    в блокноте intro. Извиняюсь за лишние пробелы в ссылке. Иначе форум ее режет.
     
    Последний раз редактировалось Waif; 04.02.2020, 16:33.
    Do not go where the path may lead, go instead where there is no path and leave a trail.
    Ralph Waldo Emerson

    Комментарий

    • #3 Свернуть

      Ещё один пост про загрузку данных. На этот раз я покажу, как можно стянуть данные из интернета. Данные будут браться у брокера ОАНДА (меня начинает раздражать цензура), с использованием их API. Начнем:

      Нажмите на изображение для увеличения.

Название:	4.png
Просмотров:	1
Размер:	16.2 Кб
ID:	28095171

      Первая строка - обычный импорт.
      Во второй строке мы задаем токен и номер аккаунта от ОАНДА. У меня они импортируются из переменных локального окружения, но вы можете задать их в явном виде. Это обычные строки.

      Нажмите на изображение для увеличения.

Название:	5.png
Просмотров:	1
Размер:	66.6 Кб
ID:	28095172

      Собственно, сама функция загрузки. Мы конструируем url-адрес, http-заголовок (нужен для авторизации), и отправляем обычный get-запрос. Так же в запросе мы передаем дополнительные параметры в виде словаря.
      Метод json() объекта response возвращает нам словарь с довольно сложной вложенной структурой. Немного упростим её и сконструируем объект DataFrame. На этом все. возвращает полученный датафрейм.

      Нажмите на изображение для увеличения.

Название:	6.png
Просмотров:	1
Размер:	34.4 Кб
ID:	28095173

      Теперь мы можем загрузить наши данные и посмотреть на них.

      Хотел дать ссылку, на то, какие параметры может принимать наша функция, но форум её цензурит. Так что параметры будут в виде картинок )

      Нажмите на изображение для увеличения.

Название:	params.png
Просмотров:	1
Размер:	184.1 Кб
ID:	28095292

      Ну и какие значения может принимать параметр granularity (таймфрейм)

      Нажмите на изображение для увеличения.

Название:	gran.png
Просмотров:	1
Размер:	87.8 Кб
ID:	28095291

      Если кому интересно, то может самостоятельно почитать документацию по API. Она довольно хорошая и подробная. Пока писал этот пост, возникла идея, показать пример написания простого торгового робота на данном API. Но пока, это только задумка. Посмотрим как будет со временем.

      На сегодня все. Весь код доступен на
      g i t h u b.com/extlife/data_analysis
      в блокноте *****_history.
         
      Do not go where the path may lead, go instead where there is no path and leave a trail.
      Ralph Waldo Emerson

      Комментарий

      • #4 Свернуть

        Сегодня хочу показать пример создания простого торгового алгоритма с помощью Python. Идея очень простая, мы будем считать идущие подряд одинаковые свечи (медвежьи или бычьи) и пытаться найти статистическое преимущество. Я назвал этот алгоритм "Детский" )
        В качестве подопытного был взят дневной график EURUSD за период с 01.02.2017 по 01.02.2020

        Нажмите на изображение для увеличения.

Название:	3_001.png
Просмотров:	2
Размер:	51.6 Кб
ID:	28101309

        Импортируем нужные пакеты, загружаем наши данные и смотрим, что получилось.

        Нажмите на изображение для увеличения.

Название:	3_002.png
Просмотров:	2
Размер:	67.8 Кб
ID:	28101308

        Добавляем колонку Bull в которой хранится истина если цена закрытия выше цены открытия, в противном случае - ложь. В колонке Count мы считаем идущие подряд свечи. Так же добавляем колонку NextCount. Это просто наша колонка Count сдвинутая на один шаг назад. Она нам пригодится.

        Нажмите на изображение для увеличения.

Название:	3_003.png
Просмотров:	2
Размер:	18.8 Кб
ID:	28101307

        Строим простую таблицу сопряженности между Count и NextCount. На этом почти все. Наша таблица содержит абсолютные величины. Нам бы хотелось, чтобы они были относительными. Исправим это.

        Нажмите на изображение для увеличения.

Название:	3_004.png
Просмотров:	2
Размер:	28.0 Кб
ID:	28101306

        Смотрим на нашу таблицу и видим, что вероятность того, что после 5 идущих подряд одинаковых свечей, будет 6 свеча того же цвета 42% и на следующих шагах продолжает падать. Используем это. Мы будем продавать после 5 подряд бычьих свечей и покупать после 5 медвежьих свечей. Ну и наконец осталось оценить, сколько мы могли бы заработать, торгуя по этой стратегии )

        Нажмите на изображение для увеличения.

Название:	3_005.png
Просмотров:	2
Размер:	59.0 Кб
ID:	28101310

        Кому интересно, могут взять другие валютные пары, другие таймфреймы и поискать там закономерности. На сегодня все. Весь код доступен на
        g i t h u b.com/extlife/data_analysis
        в блокноте baby_algo.
           
        Последний раз редактировалось Waif; 07.02.2020, 20:36.
        Do not go where the path may lead, go instead where there is no path and leave a trail.
        Ralph Waldo Emerson

        Комментарий

        • #5 Свернуть

          Спасибо за статьи. Дружище, тут ссылки не приветствуются, поэтому невозможно писать совершенно. Где то на жж или на своем домене это будет однозначно плодотворнее.
          Overgrow the world.

          Комментарий

          • #6 Свернуть

            Здравствуйте. Сегодня я хотел бы показать реализацию простого бэктеста на Python. В предыдущем посте для оценки состояния нашего счета я использовал векторизованный бэктест. Этот способ не всегда хорош и дает приблизительную оценку. Нам бы хотелось, чтобы наш тест был более приближен к тому, что происходит на рынке. Приступим.

            Загрузим нужные пакеты и определим несколько простых классов.
            Класс Tick. Я предполагаю, что данные для тестирования мы будем получать в виде свечей. Класс Tick просто содержит поля для времени, цен OHLC и объема

            Класс Source. Это наш источник котировок. Данные мы можем получить разными способами: загрузить из интернета, прочитать из файла или базы данных и т.д. Создадим базовый класс от которого потом будем наследоваться для конкретной реализации. Он имеет одно поле tick_hadler (обработчик наших тиков) и абстрактный метод run(), который каким-то образом должен генерировать тики и передавать их обработчику.

            Класс Order. Тоже простой класс, содержащий только поля.

            Нажмите на изображение для увеличения.

Название:	05_001.png
Просмотров:	1
Размер:	74.1 Кб
ID:	28133424

            Класс Position. Этот класс будет отвечать за подсчет нашей прибыли в позиции. Позицию мы можем обновить двумя способами: либо добавив что-то в нее (метод update_by_tade()) , либо просто по приходу котировки обновить нашу плавающую прибыль (метод update_by_market()).

            Нажмите на изображение для увеличения.

Название:	05_002.png
Просмотров:	1
Размер:	62.2 Кб
ID:	28133423

            Класс Strategy. Базовый класс от которого будут наследоваться все наши стратегии. Имеет поле ordrer_handler в котором храниться обработчик наших ордеров, абстрактный метод by_tick() (как должна наша стратегия реагировать на приход новой котировки), абстрактный метод by_position() (как должна реагировать стратегия на изменение позиции) и метод send_order(), который будет передавать наши ордера обработчику.

            Нажмите на изображение для увеличения.

Название:	05_003.png
Просмотров:	1
Размер:	32.3 Кб
ID:	28133422

            Класс Backtest. Он и будет заниматься тестированием. В качестве параметров он принимает источник котировок и стратегию. Тут ничего сложного. Инициализируем наши поля, назначаем обработчики и запускаем генерацию тиков.

            Нажмите на изображение для увеличения.

Название:	05_004.png
Просмотров:	1
Размер:	42.3 Кб
ID:	28133421

            Метод update_by_tick() отвечает за то, как наш тест должен реагировать на приход нового тика. Сначала мы должны просмотреть книгу ордеров и если там есть не исполненные ордера, обработать их; затем мы передаем тик стратегии для генерации сигналов и выставления ордеров; и наконец обновляем наше эквити.

            Метод update_by_order() отвечает за обработку ордеров, которые генерирует нам стратегия. Он просто добавляет их в нашу книгу заявок.

            Метод update_orderbook() пробегается по нашей книге заявок, если ордер является рыночным, то он его исполняет (метод fill_order()). После этого из книги заявок удаляются все исполненные ордера (метод remove_filled_orders()).

            Метод update_equity() обновляет нашу плавающую прибыль, а также записывает в датафрейм statement текущее состояние нашего счета.

            Нажмите на изображение для увеличения.

Название:	05_005.png
Просмотров:	1
Размер:	120.4 Кб
ID:	28133420

            На этом почти все. Нам только осталось написать конкретные реализации для классов Source и Strategy.
            Напишем класс CSVSource, который будет читать данные из csv-файла.

            Нажмите на изображение для увеличения.

Название:	05_006.png
Просмотров:	1
Размер:	55.4 Кб
ID:	28133419

            И пример простой стратегии. Через каждые 5 свечей она будет генерировать сигнал на покупку, а потом на продажу.

            Нажмите на изображение для увеличения.

Название:	05_007.png
Просмотров:	1
Размер:	53.0 Кб
ID:	28133418

            Теперь у нас все готово, чтобы запустить наш бэктест.

            Нажмите на изображение для увеличения.

Название:	05_008.png
Просмотров:	1
Размер:	87.9 Кб
ID:	28133417

            После теста мы можем посмотреть на описание нашего стейта.

            Нажмите на изображение для увеличения.

Название:	05_009.png
Просмотров:	1
Размер:	22.2 Кб
ID:	28133416

            И построить график нашей реализованной и плавающей прибыли.

            Нажмите на изображение для увеличения.

Название:	05_010.png
Просмотров:	1
Размер:	64.6 Кб
ID:	28133415

            Получилось не очень прибыльно ) Но этого достаточно, чтобы оценить, что наш бэктест работает как надо. Конечно, тут еще много того, что можно улучшить. В настоящий момент наш тест умеет обрабатывать только рыночные ордера. Можно реализовать поддержку стоп и лимит заявок. Так же наша система тестирования пока не учитывает спред, что на больших таймфреймах не является такой уж и большой проблемой, но может приводить к чрезмерно завышенный ожиданиям на малых. Можно добавить в наш ордер стоплосс и тейкпрофит, которые по сути являются просто стоп и лимит заявками и т.д.
            Кому интересно, могут поковыряться в коде и подправить его.
            На сегодня все. В следующий раз я приведу пример более осмысленной торговой стратегии для нашего теста.
            Весь код доступен на
            g i t h u b.com/extlife/data_analysis
            в блокноте simple_backtest .
               
            Последний раз редактировалось Waif; 19.02.2020, 22:41.
            Do not go where the path may lead, go instead where there is no path and leave a trail.
            Ralph Waldo Emerson

            Комментарий

            • <a href="https://www.instaforex.org/ru/?x=ruforum">InstaForex</a>
            • #7 Свернуть

              Здравствуйте. Как и обещал, привожу пример более адекватной торговой стратегии и ее бэктест.
              Для удобства работы, определения из предыдущего поста были вынесены в отдельный модуль. Чтобы протестировать нашу стратегию нам надо реализовать экземпляр класса Strategy. Все остальное у нас уже готово.
              Теперь о стратегии. В литературе часто в качестве примера алгоритмической торговой стратегии приводится стратегия возврата к среднему. Не будем и мы нарушать традицию. Идея строится на нормальности распределения приращения цен (что является только допущением).

              Нажмите на изображение для увеличения.

Название:	norm.png
Просмотров:	1
Размер:	65.8 Кб
ID:	28143682

              По свойству нормального распределения, наши данные распределены симетрично вокруг некого среднего и 64% всех наблюдений лежат в диапазоне +-1 стандартное отклонение. А в диапазоне +-1,96 стандартных отклонений лежат 95% всех наблюдений. Т.е. вероятность отклониться слишком сильно в право или лево очень мала и наши данные опять будут стремиться вернуться к теоретическому среднему. Воплотим эту идею.

              Нажмите на изображение для увеличения.

Название:	006_001.png
Просмотров:	1
Размер:	105.9 Кб
ID:	28143685

              В конструкторе __init__() инициализируем нужные нам поля. Для анализа нам нужна история цен, так что реализуем метод store_prices(), который будет сохранять в датафрей котировки. Реализуем два обязательных метода by_tick() и by_position(). В методе by_position() мы просто проверяем, в какую сторону у нас сейчас открыта позиция (на покупку или продажу). В методе by_tick() мы сначала сохраняем нашу котировку, потом генерируем сигнал и если он есть, выставляем ордер. Метод signal() генерирует наши сигналы. Мы берем последние N котировок, считаем их процентное приращение. Далее выполняем z-стандартизацию (приводим наши данные к виду, где среднее значение наших данных равно 0, а стандартное отклонение 1) и берем значение для последнего тика. Т.е. если приращение цены на последнем тике сильно отклонилось в лево и у нас нет открытых ордеров на покупку мы встаем в лонг. Если приращение цены сильно отклонилось в право и нет открытых ордеров на продажу мы встаем в шорт.

              Со стратегией закончили. Теперь можно ее протестировать. В качестве источника котировок возьмем класс CSVSource, котрый мы уже писали. Создаем бэктест, передаем ему источник котировок и нашу стратегию. Запускаем.

              Можем посмотреть описание нашего стейта.

              Нажмите на изображение для увеличения.

Название:	006_002.png
Просмотров:	1
Размер:	118.8 Кб
ID:	28143684

              И построить график реализованной и плавающей прибыли. Как видим эта стратегия более прибыльна, чем наша первая рандомная стратегия из предыдущего поста.

              Нажмите на изображение для увеличения.

Название:	006_003.png
Просмотров:	1
Размер:	44.2 Кб
ID:	28143683

              На этом все. Весь код доступен на
              g i t h u b.com/extlife/data_analysis
              в блокноте mean_reverting
               
              Do not go where the path may lead, go instead where there is no path and leave a trail.
              Ralph Waldo Emerson

              Комментарий

              Сейчас онлайн

              working...
              X