Машинное обучение для статистического арбитража I: управление данными и визуализация

Этот пример показывает методы для управления, обработки и визуализации больших сумм финансовых данных в MATLAB®. Это - часть серии связанных примеров на машинном обучении для статистического арбитража (см. Приложения Машинного обучения).

Работа с Большими данными

Финансовые рынки, с электронными обменами, такими как NASDAQ, выполняющая заказы на масштабе времени миллисекунд, генерируют огромное количество данных. Потоки данных могут быть добыты для статистических арбитражных возможностей, но традиционные методы для того, чтобы обработать и хранить динамическую аналитическую информацию могут быть разбиты большими данными. К счастью, новые вычислительные подходы появились, и MATLAB имеет массив инструментов для реализации их.

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

Файлы данных

Это использование в качестве примера один торговый день NASDAQ обменивается данными [2] на одной безопасности (INTC) в выборке, обеспеченной LOBSTER [1] и включенной с Financial Toolbox™ в zip-файл LOBSTER_SampleFile_INTC_2012-06-21_5.zip. Извлеките содержимое zip-файла в вашу текущую папку. Расширенные файлы, включая два файла CSV данных и текстовый файл LOBSTER_SampleFiles_ReadMe.txt, используйте 93,7 Мбайта памяти.

unzip("LOBSTER_SampleFile_INTC_2012-06-21_5.zip");

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

Данные об уровне 5 (пять уровней далеко от недорогого с обеих сторон) содержатся в двух файлах CSV. Извлеките торговую дату из имени файла сообщений.

MSGFileName = "INTC_2012-06-21_34200000_57600000_message_5.csv";   % Message file (description of data)
LOBFileName = "INTC_2012-06-21_34200000_57600000_orderbook_5.csv"; % Data file

[ticker,rem] = strtok(MSGFileName,'_');
date = strtok(rem,'_'); 

Хранение данных

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

Используйте tabularTextDatastore создать хранилища данных для сообщения и файлов данных. Поскольку файлы содержат данные с различными форматами, создают хранилища данных отдельно. Проигнорируйте типовые заголовки столбцов (например, VarName1) путем установки 'ReadVariableNames' аргумент пары "имя-значение" false. Замените заголовки на описательные имена переменных, полученные из LOBSTER_SampleFiles_ReadMe.txt. Установите 'ReadSize' аргумент пары "имя-значение" 'file' позволить столь же отформатированным файлам быть добавленными к существующим хранилищам данных в конце каждого торгового дня.

DSMSG = tabularTextDatastore(MSGFileName,'ReadVariableNames',false,'ReadSize','file');
DSMSG.VariableNames = ["Time","Type","OrderID","Size","Price","Direction"];

DSLOB = tabularTextDatastore(LOBFileName,'ReadVariableNames',false,'ReadSize','file');
DSLOB.VariableNames = ["AskPrice1","AskSize1","BidPrice1","BidSize1",...
                       "AskPrice2","AskSize2","BidPrice2","BidSize2",...
                       "AskPrice3","AskSize3","BidPrice3","BidSize3",...
                       "AskPrice4","AskSize4","BidPrice4","BidSize4",...
                       "AskPrice5","AskSize5","BidPrice5","BidSize5"];

Создайте объединенный datastore путем выбора Time и данные об уровне 3.

TimeVariable = "Time";
DSMSG.SelectedVariableNames = TimeVariable;

LOB3Variables = ["AskPrice1","AskSize1","BidPrice1","BidSize1",...
                 "AskPrice2","AskSize2","BidPrice2","BidSize2",...
                 "AskPrice3","AskSize3","BidPrice3","BidSize3"];
DSLOB.SelectedVariableNames = LOB3Variables;
                               
DS = combine(DSMSG,DSLOB);         

Можно предварительно просмотреть первые несколько строк в объединенном datastore, не загружая данные в память.

DSPreview = preview(DS);
LOBPreview = DSPreview(:,1:5)
LOBPreview=8×5 table
    Time     AskPrice1    AskSize1    BidPrice1    BidSize1
    _____    _________    ________    _________    ________

    34200    2.752e+05       66       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   

Предварительный просмотр показывает, спрашивает и предлагает цену при касании, означая данные об уровне 1, которые являются самыми близкими к недорогому. Единицы измерения времени спустя секунды после полуночи единицы измерения цены являются временами сумм в долларах 10,000, и единицы размера являются количеством долей (см. LOBSTER_SampleFiles_ReadMe.txt).

Длинные массивы и расписания

Длинные массивы работают с данными, которые не помещаются в память, поддержанными datastore с помощью метода MapReduce (см. Длинные массивы для Данных, которые не помещаются в память). Когда вы используете MapReduce, длинные массивы остаются неоцененными, пока вы не выполняете определенные расчеты, которые используют данные.

Установите среду выполнения для MapReduce к локальному сеансу работы с MATLAB, вместо того, чтобы использовать Parallel Computing Toolbox™, путем вызова mapreducer(0). Затем создайте длинный массив из datastore DS при помощи tall. Предварительно просмотрите данные в длинном массиве.

mapreducer(0)
DT = tall(DS);

DTPreview = DT(:,1:5)
DTPreview =

  Mx5 tall table

    Time     AskPrice1    AskSize1    BidPrice1    BidSize1
    _____    _________    ________    _________    ________

    34200    2.752e+05       66       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      400   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   
    34200    2.752e+05      166       2.751e+05      300   
      :          :           :            :           :
      :          :           :            :           :

Расписания позволяют вам выполнять операции, характерные для временных рядов (см. Создание объекта Timetable). Поскольку данные о LOB состоят из параллельных временных рядов, преобразуйте DT к длинному расписанию.

DT.Time = seconds(DT.Time); % Cast time as a duration from midnight.
DTT = table2timetable(DT);

DTTPreview = DTT(:,1:4)
DTTPreview =

  Mx4 tall timetable

      Time       AskPrice1    AskSize1    BidPrice1    BidSize1
    _________    _________    ________    _________    ________

    34200 sec    2.752e+05       66       2.751e+05      400   
    34200 sec    2.752e+05      166       2.751e+05      400   
    34200 sec    2.752e+05      166       2.751e+05      400   
    34200 sec    2.752e+05      166       2.751e+05      400   
    34200 sec    2.752e+05      166       2.751e+05      300   
    34200 sec    2.752e+05      166       2.751e+05      300   
    34200 sec    2.752e+05      166       2.751e+05      300   
    34200 sec    2.752e+05      166       2.751e+05      300   
        :            :           :            :           :
        :            :           :            :           :

Отобразите все переменные в рабочем пространстве MATLAB.

whos
  Name               Size            Bytes  Class                                       Attributes

  DS                 1x1                 8  matlab.io.datastore.CombinedDatastore                 
  DSLOB              1x1                 8  matlab.io.datastore.TabularTextDatastore              
  DSMSG              1x1                 8  matlab.io.datastore.TabularTextDatastore              
  DSPreview          8x13             4516  table                                                 
  DT                 Mx13             4950  tall                                                  
  DTPreview          Mx5              2840  tall                                                  
  DTT                Mx12             4746  tall                                                  
  DTTPreview         Mx4              2650  tall                                                  
  LOB3Variables      1x12              780  string                                                
  LOBFileName        1x1               234  string                                                
  LOBPreview         8x5              2204  table                                                 
  MSGFileName        1x1               230  string                                                
  TimeVariable       1x1               150  string                                                
  date               1x1               156  string                                                
  rem                1x1               222  string                                                
  ticker             1x1               150  string                                                

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

Предварительно обработайте и оцените данные

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

Недорогой S и неустойчивость индексирует I используются к динамике модели LOB. Чтобы поставить их расчеты в очередь, задайте их и основу времени, в терминах DTT.

timeBase = DTT.Time;
MidPrice = (DTT.BidPrice1 + DTT.AskPrice1)/2;

% LOB level 3 imbalance index:

lambda  = 0.5; % Hyperparameter
weights = exp(-(lambda)*[0 1 2]);
VAsk = weights(1)*DTT.AskSize1 + weights(2)*DTT.AskSize2 + weights(3)*DTT.AskSize3;
VBid = weights(1)*DTT.BidSize1 + weights(2)*DTT.BidSize2 + weights(3)*DTT.BidSize3;
ImbalanceIndex = (VBid-VAsk)./(VBid+VAsk);

Индекс неустойчивости является взвешенным средним, спрашивают и предлагают объемы по обе стороны от недорогого [3]. Индекс неустойчивости является потенциальным индикатором будущей динамики цен. Переменная lambda гиперпараметр, который является параметром, заданным перед обучением, а не оцененным алгоритмом машинного обучения. Гиперпараметр может влиять на эффективность модели. Разработка функции является процессом выбора проблемно-ориентированных гиперпараметров, чтобы использовать в алгоритмах машинного обучения. Можно настроить гиперпараметры, чтобы оптимизировать торговую стратегию.

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

[t,S,I] = gather(timeBase,MidPrice,ImbalanceIndex);
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 2.2 sec
Evaluation completed in 2.3 sec

Один вызов gather выполняет несколько предварительно обработанных выражений с одной передачей через datastore.

Определите объем выборки, который является количеством меток деления или обновлениями, в данных.

numTicks = length(t)
numTicks = 581030

Ежедневные данные о LOB содержат 581 030 меток деления.

Отметьте данные контрольной точкой

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

Предварительно ожидайте основу времени с датой и снимите результат в качестве массива datetime. Сохраните получившийся массив datetime, MidPrice, и ImbalanceIndex к MAT-файлу в заданном месте.

dateTimeBase = datetime(date) + timeBase; 
Today = timetable(dateTimeBase,MidPrice,ImbalanceIndex)
Today =

  581,030x2 tall timetable

        dateTimeBase         MidPrice     ImbalanceIndex
    ____________________    __________    ______________

    21-Jun-2012 09:30:00    2.7515e+05         -0.205   
    21-Jun-2012 09:30:00    2.7515e+05       -0.26006   
    21-Jun-2012 09:30:00    2.7515e+05       -0.26006   
    21-Jun-2012 09:30:00    2.7515e+05      -0.086772   
    21-Jun-2012 09:30:00    2.7515e+05       -0.15581   
    21-Jun-2012 09:30:00    2.7515e+05       -0.35382   
    21-Jun-2012 09:30:00    2.7515e+05       -0.19084   
    21-Jun-2012 09:30:00    2.7515e+05       -0.19084   
             :                  :               :
             :                  :               :
location = fullfile(pwd,"ExchangeData",ticker,date);
write(location,Today,'FileType','mat')
Writing tall data to folder /tmp/BR2020bd_1459859_105924/mlx_to_docbook15/tp0d1effde/finance-ex97702880/ExchangeData/INTC/2012-06-21
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 2.7 sec
Evaluation completed in 2.9 sec

Файл записан однажды, в конце каждого торгового дня. Код сохраняет данные к файлу в папке с меткой даты. Серия ExchangeData подпапки служат репозиторием исторических данных.

В качестве альтернативы можно сохранить переменные рабочей области, оцененные с gather непосредственно к MAT-файлу в текущей папке.

save("LOBVars.mat","t","S","I")

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

[MOBid,MOAsk] = gather(DTT.BidPrice1,DTT.AskPrice1);
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.8 sec
Evaluation completed in 1.9 sec
save("LOBVars.mat","MOBid","MOAsk","-append")

Оставшаяся часть этого примера использует только неоцененное длинное расписание DTT. Очистите другие переменные из рабочей области.

clearvars -except DTT 
whos
  Name            Size            Bytes  Class    Attributes

  DTT       581,030x12             4746  tall               

Визуализация данных

Чтобы визуализировать большие объемы данных, необходимо подвести итог, интервал, или произвести данные в некотором роде, чтобы уменьшать число точек, построенное на экране.

Снимок состояния LOB

Один метод визуализации должен оценить только выбранную подвыборку данных. Создайте снимок состояния LOB в определенное время суток (11:00).

sampleTimeTarget = seconds(11*60*60);               % Seconds after midnight
sampleTimes = withtol(sampleTimeTarget,seconds(1)); % 1 second tolerance
sampleLOB = DTT(sampleTimes,:);

numTimes = gather(size(sampleLOB,1))
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.9 sec
Evaluation completed in 2.1 sec
numTimes = 23

Существует 23 метки деления в течение одной секунды после 11:00. Для снимка состояния используйте метку деления, самую близкую к midtime.

sampleLOB = sampleLOB(round(numTimes/2),:);
sampleTime = sampleLOB.Time;

sampleBidPrices = [sampleLOB.BidPrice1,sampleLOB.BidPrice2,sampleLOB.BidPrice3];
sampleBidSizes  = [sampleLOB.BidSize1,sampleLOB.BidSize2,sampleLOB.BidSize3];
sampleAskPrices = [sampleLOB.AskPrice1,sampleLOB.AskPrice2,sampleLOB.AskPrice3];
sampleAskSizes  = [sampleLOB.AskSize1,sampleLOB.AskSize2,sampleLOB.AskSize3];

[sampleTime,sampleBidPrices,sampleBidSizes,sampleAskPrices,sampleAskSizes] = ...
    gather(sampleTime,sampleBidPrices,sampleBidSizes,sampleAskPrices,sampleAskSizes);
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 2: Completed in 1.8 sec
- Pass 2 of 2: Completed in 1.9 sec
Evaluation completed in 4 sec

Визуализируйте выборку ограниченных данных, возвращенную gather при помощи bar.

figure
hold on

bar((sampleBidPrices/10000),sampleBidSizes,'r')
bar((sampleAskPrices/10000),sampleAskSizes,'g')
hold off

xlabel("Price (Dollars)")
ylabel("Number of Shares")
legend(["Bid","Ask"],'Location','North')
title(strcat("Level 3 Limit Order Book: ",datestr(sampleTime,"HH:MM:SS")))

Глубина рынка

Некоторые функции визуализации работают непосредственно с длинными массивами и не требуют использования gather (смотрите Визуализацию Длинных массивов). Функции автоматически выборочные данные, чтобы уменьшить плотность пикселей. Визуализируйте уровень 3 суточная глубина рынка, который показывает эволюцию времени ликвидности, при помощи plot с длинным расписанием DTT.

figure
hold on

plot(DTT.Time,-DTT.BidSize1,'Color',[1.0 0 0],'LineWidth',2)
plot(DTT.Time,-DTT.BidSize2,'Color',[0.8 0 0],'LineWidth',2)
plot(DTT.Time,-DTT.BidSize3,'Color',[0.6 0 0],'LineWidth',2)

plot(DTT.Time,DTT.AskSize1,'Color',[0 1.0 0],'LineWidth',2)
plot(DTT.Time,DTT.AskSize2,'Color',[0 0.8 0],'LineWidth',2)
plot(DTT.Time,DTT.AskSize3,'Color',[0 0.6 0],'LineWidth',2)

hold off

xlabel("Time")
ylabel("Number of Shares")
title("Depth of Market: Intraday Evolution")
legend(["Bid1","Bid2","Bid3","Ask1","Ask2","Ask3"],'Location','NorthOutside','Orientation','Horizontal');

Чтобы отобразить детали, ограничьте временной интервал.

xlim(seconds([45000 45060]))
ylim([-35000 35000])
title("Depth of Market: One Minute")

Сводные данные

Этот пример начинает основы работы с большими данными, и в и из памяти. Это показывает, как настроить, объединить, и обновить внешние хранилища данных, затем создайте длинные массивы для предварительной обработки данных, не выделяя переменные в рабочем пространстве MATLAB. gather функционируйте данные о передачах в рабочую область для расчета и последующего анализа. Пример показывает, как визуализировать данные через выборку данных или функциями построения графика MATLAB, которые работают непосредственно с данными, которые не помещаются в память.

Ссылки

[1] Книжные Данные о Лимитном приказе LOBSTER. Берлин: frischedaten UG (haftungsbeschränkt).

[3] Рубисов, Антон Д. "Статистический Арбитраж Используя Книжную Неустойчивость Лимитного приказа". Магистерская диссертация, Университет Торонто, 2015.

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте