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