Cython для трейдинга – скорость имеет значение

Python замечательный язык, де факто питон стал OpenSource альтернативой множеству дорогостоящих математических пакетов в научной среде, трейдинг здесь не является исплючением. Я считаю, что трейдинг  – это больше наука, чем искусство. Весь прошлый месяц я делал инструмент, который выполняет тонны расчетов, при чем он это делает на питоне. А как любой интерпретируемый язык – питон достаточно медленный, и прожорливый по части памяти, но в умелых руках его скорости могут достигать скоростей C/C++ языков! Поделюсь небольшим опытом оптимизации расчетов на питоне, а также поделюсь single pass алгоритмом для расчета СКО на Питоне. Сразу скажу, для этого конкретного кода мне удалось добиться увеличения производительности кода в 30 (тридцать) раз!

Вот тот самый код, который считает СКО, среднее и количество в online режиме, это позволяет получить большой выигрыш по производительности и по использованию памяти. Если кто не знает, обычный расчет СКО подразумевает 2 прохода по всем данным, сначала рассчитывается средняя, потом среднеквадратическое отклонение от нее. Более того большинство online алгоритмов расчета СКО не проходили проверку на стабильность, я тупо сравнивал с numpy.std(), и мой алгоритм имеет 100% сходимость с numpy. Хотя алгоритм конечно не мой, я откопал его где-то в интернетах и переписал на питон.

class Stats_py:
    k = 0.0
    Mk = 0.0
    Qk = 0.0
    def __init__(self):
        self.k = 0.0
        
    def add(self, x):
        self.k += 1
        if self.k == 1.0:    
            self.Mk = x
            self.Qk = 0.0
        else:
            d = x - self.Mk
            self.Qk += (self.k-1.0)*d*d/self.k
            self.Mk += d / self.k
    
    def std(self):
        return sqrt(self.Qk/self.k)
    def mean(self):
        return self.Mk
    def count(self):
        return self.k

Делаем простую проверку на скорость в IPython:

values = np.random.random(10000)
s = Stats_py()
for x in values:
    s.add(x)  
print np.std(values), s.std()

%timeit s.add(1)
------
0.289223020474 0.289223020474
100000 loops, best of 3: 2.93 µs per loop

Как вы видите цифры бьються до последнего знака, а выполнение одного вызова функции add() занимает 2.93 микросекунды = 2930 наносекунд. С одной стороны это очень мало, с другой стороны когда нужно совершить миллиарды итераций это время начинает уже сильно ощущаться.

Теперь давайте выжмем из этого кода все на что он способен! Для этого нам нужно взять в руки напильник Cython и научиться с ним работать. IPython Notebook предоставляет отличную возможность писать и отлаживать код Cython прямо в браузере! Для этого есть специальный %%cyton magiс, примеры работы с ним можно посмотреть в разделе Cython Magic Functions Extension.

Оптимизация cython

Читать далее…

Python+Pandas для исследований рынка

Решил запостить небольшую сказку из чата, где я показал простую задачу: скачать котировки 2х рядов, объединить их и подготовить данные для последующей работы.

[16:59] Тема: скачка и формирование данных с помощью python+pandas
[17:00] Задача: скачать с сайта ММВБ данные по индексам РЕПО + ММВБ, объединить их, и подготовить для анализа
[17:00] Все лезим и качаем URL http://www.micex.ru/issrpc/marketdata/stock/index/history/by_ticker/index_history_MICEXEQRRON.csv?secid=MICEXEQRRON&lang=ru
[17:01] pandas это тоже может сделать, более того, он автоматом распарсит эту csv, и распознает дату/время, и сделает ее индексом.
[17:02] индекс может быть любым, в нашем случае это дата время
[17:03] шаг 1: качаем данные по РЕПО, и конвертим их в объект DataFrame

Selection_628

[17:04] DataFrame – это как таблица в БД, в нашем случае это временные ряды OHLC которые отдала нам биржа
[17:05] дальше, нам нужно переименовать наш DF, чтобы не было конфликта колонок CLOSE когда мы будем объединять их с индексом ММВБ

Selection_627

[17:07] шаг 2: качаем данные индекса ММВБ
[17:08] на сайте биржи эти данные с 1997 года, а индексы репо с 2006. Поэтому целесообразно часть данных до 2006 года убрать.

Selection_622

[17:09] Хотя при объединении 2х ДФ, Pandas мягко обойдет грабли, пропущенные данные будут заменены NaN.
[17:09] Мы просто сделали это для удобства
[17:09] дальше нам надо смержить 2 набора данных, и синхронизировать их по времени
[17:10] Синхронизация в pandas делается на лету, по значению df.index, т.к. у нас это дата-время, то все будет корректно выровнено по времени
[17:11] Шаг 3: приводим все в комфортный для понимания вид, и удаляем ненужные поля из ДФ

Selection_629

[17:12] дальше можно что-то начать анализировать
[17:13] вот наш готовый ДФ

Selection_625

[17:19] вот пример как посчитать MA, и построить отношение

Selection_626

Более подробно исходный код и результаты его работы можно посмотреть по ссылке:
http://nbviewer.ipython.org/4153430/

Рисерч выполнен с помощью IPython Notebook

Python: формула оценки последовательности убыточных сделок

Риск системы, и ее просадка во многом зависит от последовательности нескольких убыточных сделок. Как правило MaxDD возникает как серия из нескольких убытков, а не как один большой лось.

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

LoosingStreak = LN(1 / nTradesCount)/LN(1 – WinProbability)

FYI: Логарифмы натуральные. WinProbability – проценты в долях единицы, 0.6 = 60%

Я решил эту формулу численно перепроверить и написал простенький скрипт на Python.

Скрипт показывает количество убытков подряд, и их зависимость от числа сделок, при жестко заданной вероятности.

Вот результаты моделирования при Win% = 60%

14

Названия колонок:
Trades – число сделок
Theo – количество убыточных сделок подряд, по теоретической формуле
Real – количество убыточных сделок подряд, которое показало моделирование
Error – Theo – Real

Как вы видите показатели Theo и Real практически сходятся, а Error остается постоянной. Это говорит нам о том, что теоретическая формула работает.

Код на Python:

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 19 15:10:23 2012

@author: ubertrader
"""

# -*- coding: utf-8 -*-
"""
Created on Tue Jul 17 14:06:39 2012

@author: ubertrader
"""

import random 
from math import *



winperc = 0.6
MCIterations = 10000

mintr = 100
maxtr = 1000
steptr = 100

TheoStreak = []
RealStreak = []

for trcount in range(mintr, maxtr, steptr):    
    sumstreak = 0
    cnt = 0
    for mci in range(1,MCIterations):
        streak = 0
        maxstreak = 0
        
        for t in range(0, trcount):        
            if random.random() < winperc:             
                profit = 1
            else:
                profit = -1
                
            if profit > 0:            
                streak = 0
            else:            
                streak = streak + 1
                        
            maxstreak = max(streak, maxstreak)
            
        
        sumstreak = sumstreak + maxstreak
        cnt = cnt + 1
        
    #Calc streak error
    LoosingStreak = log(1/float(trcount))/log(float(1-winperc))
    avgstreak = float(sumstreak) / float(cnt)
    
    RealStreak.append(avgstreak)
    TheoStreak.append(LoosingStreak)
    

print 'Trades\tTheo\tRealAvg\tError'
idx = 0
for trcount in range(mintr, maxtr, steptr):        
    print '{0}\t{1:0.2f}\t{2:0.2f}\t{3:0.2f}'.format(trcount, TheoStreak[idx], RealStreak[idx], TheoStreak[idx] - RealStreak[idx])
    idx = idx + 1
    

    

Python: код для генерации баров из тиков

Еще один простенький скрипт на python для генерации баров из тиков.

Какие примеры дает этот код:
1. Чтение/запись файлов
2. Работа с CSV
3. Парсинг даты/времени
4. Good Practice создания ООП кода

P.S. Код достаточно медленный из-за парсинга Даты-Времени в этом месте self.Time = strptime(time[0:16], timeformat);
Читать далее…

Python: скрипт для risk management

Небольшое дополнение к посту от Aspirin и Avals. Простенькая число-дробилка, которая показывает ожидаемые параметры по системе, рассчитывает NetProfit, MaxDD, PF, %win, и число убыточных сделок подряд.

Ее можно использовать для оценки рисков по системе (risk management), т.к. как правило MaxDD одного теста нерепрезентативно, потому как может не учитывать все вероятности получения череды убыточных сделок.

Вот результат моделирования “системы” у которой avgwin = 50, avgloss = 50, win% = 50%. Теоретически мы знаем, что МО этой системы = 0. Но в зависимости от того, как падает наша монетка, мы можем получить как + так и – по этой системе.

Я прогнал 100 000 случайных генераций, по 100 трейдов с описанными выше параметрами. Что дало следующие результаты:

13

На картинке мы видим распределение случайных результатов по процентилям, 50% процентиль – это среднее значение, и оно нам подтверждает что система имеет МО = 0. Также результат показывает, что в среднем мы можем ожидать 6 убыточных сделок подряд, и есть 10% вероятность, что мы увидим 8 убытков к ряду.

Самая главная часть, состоит в том, что в 5% случаях есть вероятность увидеть просадку выше -1050, это число кстати может быть оптимистичнее, чем то что есть у вас на тестах. В силу того, что этот скрипт работает со средними значениями, его результаты несколько оптимистичны. У меня есть другой скрипт, который я опубликую для членов клуба позже.

Настройки:
1. Вероятность выигрыша в долях единицы 0.5 = 50%
winperc = 0.50
2. Средний выигрыш в % или деньгах
avgwin = 50
3. Средний проигрыш в % или деньгах
avgloss = 50
4. Минимальное число сделок в год
mintradesperyear = 100
5. Максимальное число сделок в год
maxtradesperyear = 100

FYI: Скрипт считает модель на основе годового периода, хотя это полнейшая условность.Мин и Макс число сделок в год вносит дополнительную “случайность”, можно ставить одинаковое значение.

Сам код:
Читать далее…

Python для трейдера

Python – кросс-платформенный язык, который обладает очень простым и читаемым синтаксисом. Спасибо druidkgm и Doctor Leo за то, что они обратили мое внимание на этот язык. Раньше я использовал C# для своих прикладных задач, это тоже отличный язык, но в некоторых случаях нужно написать в 3-5 раз больше кода чем на Python или Matlab, чтобы добиться решения одной и той же задачи.

Конечно же я полностью не отказался от C# и Matlab, каждый язык нужен для своих задач. Python я использую в тех случаях когда мне нужно, сделать небольшую утилитку “на коленке” и быстро получить результат.

Этот пост, будет вводным. Дам несколько ссылок на интересные ресурсы.

Python wikipedia – общее представление о языке

Python (x,y) – среда разработки Python,а по совместительству целая платформа по численному анализу, чем-то напоминает Матлаб.

Модуль для Visual Studio – вся мощь Python доступна теперь и в Visual Studio. Интеграция с Iron Pyhon а значит и c C#. Т.е. мы можем легко писать сборки на питоне и потом их легко использовать в любых C# приложениях. Обзор возможностей на русском

Также нужно отметить, что есть вариант языка с синтаксисом Python, но с возможностью доступа ко всем классам .net. IronPython Однако, нужно отметить, что эта реализация языка лишает возможности обращаться к стандартным библиотекам и модулям Python. Более того она реализована через механизм DLR (wiki) и программа “hello world!” компилируется в такую кашу кода, что хватаешься за голову. Понятно что IronPython работает медленнее, чем C# .net код, и даже медленнее чем оригинальный Python. Однако, в интернете, есть примеры приложений на C#, в которые можно встроить динамический скриптовый движок на IronPython.

Вообще Python язык сверхвысокого уровня, он может все, что может C++ или C#. На нем написаны множество приложений. У него есть даже специальные компиляторы, которые помогают ускорить работу там, где это необходимо.

Есть 2 модуля, которые нужны для работы с числами, хотя я близко с ними не сталкивался. NumPy – векторные вычисления как в Matlab. Matplotlib – библиотека вывода графиков. Оба пакета есть в Python (x,y),ссылку на этот софт я давал выше.

В следующих постах, я опубликую несколько Python скриптов, которые решают некоторые трейдерские задачи.