В этом примере показаны методы управления, обработки и визуализации больших объемов финансовых данных в MATLAB ®. Она является частью серии связанных примеров машинного обучения для статистического арбитража (см. Приложения машинного обучения).
Финансовые рынки с электронными обменами, такими как NASDAQ, выполняющие заказы в миллисекундах, генерируют огромные объемы данных. Потоки данных могут быть добыты для возможностей статистического арбитража, но традиционные методы обработки и хранения динамической аналитической информации могут быть переполнены большими данными. К счастью, появились новые вычислительные подходы, и MATLAB имеет множество инструментов для их реализации.
Основная компьютерная память обеспечивает высокоскоростной доступ, но ограниченную емкость, в то время как внешняя память обеспечивает низкоскоростной доступ, но потенциально неограниченную емкость. Вычисление происходит в памяти. Компьютер возвращает данные и результаты из внешнего хранилища.
В этом примере используется один торговый день обмена данными NASDAQ [2] по одной безопасности (INTC) в образце, предоставленном LOBSTER [1] и включенном с финансовым 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,'_');
Ежедневные потоки данных накапливаются и должны храниться. Хранилище данных - это хранилище для наборов данных, слишком больших для размещения в памяти.
Использовать 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"];
Создание объединенного хранилища данных путем выбора 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);
Можно просмотреть первые несколько строк в объединенном хранилище данных без загрузки данных в память.
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).
Массивы Tall работают с данными вне памяти, поддерживаемыми хранилищем данных с помощью метода MapReduce (см. раздел Массивы Tall для данных из памяти). При использовании MapReduce массивы tall остаются невысокими до тех пор, пока не будут выполнены определенные вычисления, использующие данные.
Установите среду выполнения для MapReduce в локальный сеанс MATLAB вместо использования Toolbox™ параллельных вычислений путем вызова mapreducer(0). Затем создайте массив высокого уровня из хранилища данных 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
: : : : :
: : : : :
Расписания позволяют выполнять операции, специфичные для временных рядов (см. Создание расписаний). Поскольку данные 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 4515 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 2203 table MSGFileName 1x1 230 string TimeVariable 1x1 150 string date 1x1 156 string rem 1x1 222 string ticker 1x1 150 string
Поскольку все данные находятся в хранилище данных, рабочая область использует мало памяти.
Массивы Tall позволяют выполнять предварительную обработку или постановку в очередь вычислений до их оценки, что улучшает управление памятью в рабочей области.
Недорогой 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.3 sec Evaluation completed in 2.5 sec
Одиночный вызов gather вычисляет несколько предварительно обработанных выражений за один проход через хранилище данных.
Определите размер выборки, который представляет собой количество засечек или обновлений в данных.
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/BR2021ad_1655202_180016/mlx_to_docbook15/tp0c5070d3/finance-ex97702880/ExchangeData/INTC/2012-06-21 Evaluating tall expression using the Local MATLAB Session: - Pass 1 of 1: Completed in 3.3 sec Evaluation completed in 3.5 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 2.1 sec Evaluation completed in 2.2 sec
save("LOBVars.mat","MOBid","MOAsk","-append")
В оставшейся части этого примера используется только невысокий график DTT. Удаление других переменных из рабочей области.
clearvars -except DTT whos
Name Size Bytes Class Attributes DTT 581,030x12 4746 tall
Для визуализации больших объемов данных необходимо суммировать, складировать или пробовать данные таким образом, чтобы уменьшить количество точек, отображаемых на экране.
Один из способов визуализации состоит в том, чтобы вычислить только выбранную субпопулу данных. Создайте снимок LOB в определенное время суток (11 часов утра).
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 2.4 sec Evaluation completed in 2.5 sec
numTimes = 23
Есть 23 клещей в течение одной секунды 11 утра. Для снимка используйте галочку, ближайшую к среднему времени.
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 2.4 sec - Pass 2 of 2: Completed in 2.3 sec Evaluation completed in 5.2 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")))

Некоторые функции визуализации работают непосредственно с массивами tall и не требуют использования gather (см. Визуализация массивов Tall). Функции автоматически производят выборку данных для уменьшения плотности пикселей. Визуализация внутридневной глубины рынка уровня 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).
[2] Исторические данные NASDAQ TotalView-ITCH. Нью-Йорк: Nasdaq, Inc.
[3] Рубисов, Антон Д. «Статистический арбитраж с использованием дисбаланса книги лимитов». Магистерская диссертация, Университет Торонто, 2015 год.