100 строк Python-кода: Автоматизируем биржевую торговлю

Если вы знакомы с финансовым рынком и владеете Python, вы можете легко автоматизировать финансовую торговлю.

Алгоритмическая торговля

Алгоритмическая торговля (алготрейдинг, algorithmic trading) – это автоматизированная с помощью компьютерных средств торговля финансовыми инструментами на основе определенного алгоритма или правила с незначительным участием или без участия человека. Торговать в автоматическом режиме можно почти любыми финансовыми инструментами: акциями, валютами, сырьем, кредитными продуктами или волатильностью. В некоторых сегментах рынка львиная доля сделок совершается именно алгоритмами. Книги «Кванты» («The Quants») Скотта Паттерсона (Scott Patterson) и «More Money Than God» Себастиана Маллаби (Sebastian Mallaby) дают хорошее представление об алгоритмической торговле и личностях, стоявших у ее истоков.

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

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

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

  • • Торговые онлайн-платформы. В настоящее время существует множество онлайн-платформ, которые предоставляют простой стандартизированный доступ к историческим данным (посредством RESTful API), данным реального времени (посредством socket API), а также обеспечивают широкий спектр средств для торговли и работы с портфелями (посредством программного API).

В этой статье мы реализуем все элементы, необходимые для полноценной алгоритмической торговли, начиная от тестирования торговой стратегии на исторических данных (бэктестинг, backtesting) до автоматической торговли в режиме реального времени.

Рассмотрим основные составляющие проекта:

  • • Стратегия. Мы выбрали моментум-стратегию (momentum strategy), представленную в публикации Moskowitz et al. «Time Series Momentum», 2012. В рамках данной стратегии мы предполагаем, что финансовый инструмент, демонстрировавший в прошлом определенную (позитивную или негативную) тенденцию, в дальнейшем будет следовать этой же тенденции.

  • • Платформа. Мы остановили свой выбор на платформе Oanda. Данная платформа позволяет торговать различные контракты на разницу цен (contract for difference, CFD), что, по сути, позволяет оперировать широким спектром финансовых инструментов, таких как валюты, фондовые индексы, сырье и др.

  • • Данные. Все исторические данные и данные реального времени для нас обеспечит платформа Oanda.

  • • Программное обеспечение. Мы будем использовать Python, мощную аналитическую библиотеку Pandas, а также несколько дополнительных библиотек.

В дальнейшем мы предполагаем, что у вас установлен Python 3.5 и основные библиотеки, такие как NumPy и Pandas. Если у вас еще нет этих средств, вы можете установить все необходимое, используя, например, дистрибутив Anaconda.

Аккаунт Oanda

На платформе Oanda (http://oanda.com) любой желающий может бесплатно зарегистрировать демо аккаунт, обеспечивающий доступ к имитации торгового процесса. После того, как аккаунт зарегистрирован, чтобы получить программный доступ к Oanda API, необходимо установить соответствующую Python-библиотеку:

pip install oandapy

Перед началом работы с библиотекой необходимо создать файл конфигурации oanda.cfg со следующим содержимым:

[oanda]
account_id = YOUR_ACCOUNT_ID
access_token = YOUR_ACCESS_TOKEN

Укажите в файле конфигурации ваш идентификатор и токен, значения которых вы можете узнать в своем аккаунте.

Выполнив следующий код, мы получаем основной объект для программного взаимодействия с платформой:

In [1]:
import configparser  # 1 
import oandapy as opy  # 2

config = configparser.ConfigParser()  # 3
config.read('oanda.cfg')  # 4

oanda = opy.API(environment='practice',
                access_token=config['oanda']['access_token'])  # 5

У нас уже есть все необходимое, чтобы начать тестирование моментум-стратегии. В частности, мы можем получить исторические данные, предоставляемые платформой. Мы будем использовать инструмент EUR_USD, основанный на обменном курсе EUR/USD.

Первым делом мы загружаем набор исторических данных и преобразуем его в DataFrame. Мы получаем дынные за два дня: 8 и 9 декабря 2016 года. Дискретность данных составляет 1 минуту. Выполним следующий код:

In [2]:

import pandas as pd # 6

data = oanda.get_history(instrument='EUR_USD', # our instrument

start='2016-12-08', # start data

end='2016-12-10', # end date

granularity='M1') # minute bars # 7

df = pd.DataFrame(data['candles']).set_index('time') # 8

df.index = pd.DatetimeIndex(df.index) # 9

df.info() # 10

В результате получим подробную характеристику набора данных:



DatetimeIndex: 2658 entries, 2016-12-08 00:00:00 to 2016-12-09 21:59:00

Data columns (total 10 columns):

closeAsk 2658 non-null float64

closeBid 2658 non-null float64

complete 2658 non-null bool

highAsk 2658 non-null float64

highBid 2658 non-null float64

lowAsk 2658 non-null float64

lowBid 2658 non-null float64

openAsk 2658 non-null float64

openBid 2658 non-null float64

volume 2658 non-null int64

dtypes: bool(1), float64(8), int64(1)

memory usage: 210.3 KB

Далее мы формализуем моментум-стратегию, вычисляя для каждого момента времени среднее логарифма доходности (mean log return) за последние 15, 30, 60 и 120 минут. Например, среднее логарифма доходности за последние 15 минут – это среднее 15 последних значений логарифма доходности. Если эта величина положительна, мы играем на повышение (go/stay long), если отрицательна – на понижение (go/stay short). Чтобы не усложнять код, мы полагаемся лишь на значение столбца closeAsk.

In [3]:

import numpy as np # 11

df['returns'] = np.log(df['closeAsk'] / df['closeAsk'].shift(1)) # 12

cols = [] # 13

for momentum in [15, 30, 60, 120]: # 14

col = 'position_%s' % momentum # 15

df[col] = np.sign(df['returns'].rolling(momentum).mean()) # 16

cols.append(col) # 17

Затем, чтобы вычислить абсолютную результативность моментум-стратегий, основанных на различных временных интервалах, необходимо умножить доходность на величины, полученные выше (предварительно выполнив сдвиг). Вот как мы это сделаем:

In [4]:

%matplotlib inline

import seaborn as sns; sns.set() # 18

strats = ['returns'] # 19

for col in cols: # 20

strat = 'strategy_%s' % col.split('_')[1] # 21

df[strat] = df[col].shift(1) * df['returns'] # 22

strats.append(strat) # 23

df[strats].dropna().cumsum().apply(np.exp).plot() # 24

Получим следующую диаграмму:

Проанализировав диаграмму, мы видим, что в течение рассматриваемого периода, сам инструмент имеет отрицательную доходность около -2%. Моментум-стратегия, основанная на 120-минутных интервалах, показывает наилучший результат, демонстрируя положительную доходность около 1.5% (без учета разницы между спросом и предложением (bid/ask spread)). По сути, данная стратегия показывает «реальную альфу»: она обеспечивает положительную доходность даже тогда, когда сам инструмент имеет отрицательную доходность.

Автоматическая торговля

Выбрав торговую стратегию, мы можем полностью автоматизировать торговые операции. Чтобы ускорить процесс, мы используем данные с дискретностью 5 секунд, вместо 1 минуты, как было при тестировании. Автоматизировать торговлю можно с помощью одного достаточно компактного класса:

In [5]:

class MomentumTrader(opy.Streamer): # 25

def __init__(self, momentum, *args, **kwargs): # 26

opy.Streamer.__init__(self, *args, **kwargs) # 27

self.ticks = 0 # 28

self.position = 0 # 29

self.df = pd.DataFrame() # 30

self.momentum = momentum # 31

self.units = 100000 # 32

def create_order(self, side, units): # 33

order = oanda.create_order(config['oanda']['account_id'],

instrument='EUR_USD', units=units, side=side,

ENGINE='market') # 34

print('\n', order) # 35

def on_success(self, data): # 36

self.ticks += 1 # 37

# print(self.ticks, end=', ')

# appends the new tick data to the DataFrame object

self.df = self.df.append(pd.DataFrame(data['tick'],

index=[data['tick']['time']])) # 38

# transforms the time information to a DatetimeIndex object

self.df.index = pd.DatetimeIndex(self.df['time']) # 39

# resamples the data set to a new, homogeneous interval

dfr = self.df.resample('5s').last() # 40

# calculates the log returns

dfr['returns'] = np.log(dfr['ask'] / dfr['ask'].shift(1)) # 41

# derives the positioning according to the momentum strategy

dfr['position'] = np.sign(dfr['returns'].rolling(

self.momentum).mean()) # 42

if dfr['position'].ix[-1] == 1: # 43

# go long

if self.position == 0: # 44

self.create_order('buy', self.units) # 45

elif self.position == -1: # 46

self.create_order('buy', self.units * 2) # 47

self.position = 1 # 48

elif dfr['position'].ix[-1] == -1: # 49

# go short

if self.position == 0: # 50

self.create_order('sell', self.units) # 51

elif self.position == 1: # 52

self.create_order('sell', self.units * 2) # 53

self.position = -1 # 54

if self.ticks == 250: # 55

# close out the position

if self.position == 1: # 56

self.create_order('sell', self.units) # 57

elif self.position == -1: # 58

self.create_order('buy', self.units) # 59

self.disconnect() # 60

Следующий фрагмент кода запускает класс MomentumTrader на выполнение. Расчет моментум-стратегии выполняется на основе интервалов по 12 наблюдений. Класс автоматически прекращает торговлю после получения 250 блоков данных. Это значение выбрано произвольно, чтобы быстро продемонстрировать работу класса MomentumTrader.

In [6]:

mt = MomentumTrader(momentum=12, environment='practice',

access_token=config['oanda']['access_token'])

mt.rates(account_id=config['oanda']['account_id'],

instruments=['DE30_EUR'], ignore_heartbeat=True)

Вывод, представленный ниже, показывает отдельные торговые операции, выполняемые классом MomentumTrader, в процессе демонстрации:

{'price': 1.04858, 'time': '2016-12-15T10:29:31.000000Z', 'tradeReduced': {}, 'tradesClosed': [], 'tradeOpened': {'takeProfit': 0, 'id': 10564874832, 'trailingStop': 0, 'side': 'buy', 'stopLoss': 0, 'units': 100000}, 'instrument': 'EUR_USD'}

{'price': 1.04805, 'time': '2016-12-15T10:29:46.000000Z', 'tradeReduced': {}, 'tradesClosed': [{'side': 'buy', 'id': 10564874832, 'units': 100000}], 'tradeOpened': {'takeProfit': 0, 'id': 10564875194, 'trailingStop': 0, 'side': 'sell', 'stopLoss': 0, 'units': 100000}, 'instrument': 'EUR_USD'}

{'price': 1.04827, 'time': '2016-12-15T10:29:46.000000Z', 'tradeReduced': {}, 'tradesClosed': [{'side': 'sell', 'id': 10564875194, 'units': 100000}], 'tradeOpened': {'takeProfit': 0, 'id': 10564875229, 'trailingStop': 0, 'side': 'buy', 'stopLoss': 0, 'units': 100000}, 'instrument': 'EUR_USD'}

{'price': 1.04806, 'time': '2016-12-15T10:30:08.000000Z', 'tradeReduced': {}, 'tradesClosed': [{'side': 'buy', 'id': 10564875229, 'units': 100000}], 'tradeOpened': {'takeProfit': 0, 'id': 10564876308, 'trailingStop': 0, 'side': 'sell', 'stopLoss': 0, 'units': 100000}, 'instrument': 'EUR_USD'}

{'price': 1.04823, 'time': '2016-12-15T10:30:10.000000Z', 'tradeReduced': {}, 'tradesClosed': [{'side': 'sell', 'id': 10564876308, 'units': 100000}], 'tradeOpened': {'takeProfit': 0, 'id': 10564876466, 'trailingStop': 0, 'side': 'buy', 'stopLoss': 0, 'units': 100000}, 'instrument': 'EUR_USD'}

{'price': 1.04809, 'time': '2016-12-15T10:32:27.000000Z', 'tradeReduced': {}, 'tradesClosed': [{'side': 'buy', 'id': 10564876466, 'units': 100000}], 'tradeOpened': {}, 'instrument': 'EUR_USD'}

На рисунке ниже показано приложение Oanda fxTrade Practice, где мы видим класс MomentumTrader в действии.

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

Заключение

В данной статье мы рассмотрели быстрый старт в алгоритмической торговле, для которого требуется менее 100 строк Python-кода. Мы обсудили все основные этапы реализации подобных проектов: получение исторических данных для тестирования, тестирование стратегии, автоматизация торговых операций на основе выбранной стратегии. Представленный код является отправной точкой, откуда можно двигаться в различных направлениях. Например, можно использовать различные стратегии, задействовать различные инструменты или работать с несколькими инструментами одновременно.

О популярности алгоритмической торговли свидетельствует появление различных типов торговых платформ. Например, создатели Quantopian – онлайн-платформы для тестирования стратегий алгоритмической торговли – сообщили в конце 2016 года о привлечении более 100000 пользователей. Торговые онлайн-платформы, подобные Oanda, а также специализирующиеся на криптовалюте, такие как Gemini, позволяют очень быстро начать торговлю на реальном рынке, присоединившись к тысячам трейдеров, живущих во всех точках земного шара.

Добавить комментарий

Ваш адрес email не будет опубликован.

закрыть

Поделиться

Отправить на почту
закрыть

Вход

закрыть

Регистрация

+ =