Быстрое соединение data.table с временными рядами

У меня есть два набора данных с ценами валютных данных (максимум, минимум, открытие и закрытие) на двух разных таймфреймах (1 час и 5 минут).

У меня есть целевые цены для каждой строки данных 1-часового таймфрейма и целевое направление для сделки (либо 1, либо -1).

Для сделок с направлением «1» я пытаюсь найти первую точку на 5-минутном графике, где «минимум» <= целевого уровня. И наоборот, для сделок с направлением «-1» я хочу найти первую точку на 5-минутном графике, где «максимум» >= целевой уровень сделки.

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

Проблема, с которой я сталкиваюсь на практике, заключается в том, что я смотрю на периоды времени, охватывающие 10-20 лет, что делает соединения очень медленными. Я установил пример ниже с 2016 по 2022 год, чтобы он не был слишком медленным на моем компьютере, но если вы продлите его до более чем 10 лет, это действительно станет проблемой.

Это может быть то, с чем мне приходится жить, но я ищу руководство по двум вещам:

  1. Есть ли более быстрый/более эффективный способ достижения того, что я описал ниже?
  2. Вы можете видеть, что в конце я разделил сделки на покупку и продажу на два соединения. Есть ли способ объединить это в одно соединение? На самом деле это не так важно, так как не занимает слишком много «места» в моем коде, но меня это интересует в образовательных целях.

Заранее огромное спасибо, Фил

# Load required packages
library(data.table)
library(dplyr)

# Define timeframes for the data
Start <- as.POSIXct("2016-01-01 00:00:00")
End <- as.POSIXct("2022-01-01 23:55:00")

Hours <- floor(as.numeric(difftime(End,Start,units = "hours"))) + 1
Minutes <- floor(as.numeric(difftime(End,Start,units = "mins")) / 5) + 1

# Create the Hourly data
set.seed(123)
hourly_prices <- data.table(
  datetime = seq(Start, End, by = "hour"),
  open = rnorm(Hours, mean = 100, sd = 1),
  high = rnorm(Hours, mean = 101, sd = 1),
  low = rnorm(Hours, mean = 99, sd = 1),
  close = rnorm(Hours, mean = 100, sd = 1),
  Direction = sample(c(1,-1),Hours,replace = T)) %>%
  .[,Target_price := ifelse(Direction == -1,rnorm(.N, mean = 104, sd = 1),rnorm(.N,mean = 97,sd = 1))]

# Create the 5-minute data
set.seed(456)
minute_prices <- data.table(
  datetime = seq(Start, End, by = "5 min"),
  open = rnorm(Minutes, mean = 100, sd = 1),
  high = rnorm(Minutes, mean = 101, sd = 1),
  low = rnorm(Minutes, mean = 99, sd = 1),
  close = rnorm(Minutes, mean = 100, sd = 1),
  Position = seq_len(Minutes))

# Join the two data.tables to find the first point at which price passes the target levels
hourly_prices[(Direction == 1),Location := minute_prices[.SD, on = .(datetime > datetime, low <= Target_price),mult = "first",x.Position]]
hourly_prices[(Direction == -1),Location := minute_prices[.SD, on = .(datetime > datetime, high >= Target_price),mult = "first",x.Position]]

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

Waldi 16.02.2023 07:05
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Laravel - это мощный PHP-фреймворк, используемый для создания масштабируемых и надежных веб-приложений. Одним из преимуществ Laravel является его...
Что такое двойные вопросительные знаки (??) в JavaScript?
Что такое двойные вопросительные знаки (??) в JavaScript?
Как безопасно обрабатывать неопределенные и нулевые значения в коде с помощью Nullish Coalescing
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание API-ресурса Laravel может быть непростой задачей. Она требует глубокого понимания возможностей Laravel и лучших практик, чтобы обеспечить...
Как сделать компонент справочного центра с помощью TailwindCSS
Как сделать компонент справочного центра с помощью TailwindCSS
Справочный центр - это веб-сайт, где клиенты могут найти ответы на свои вопросы и решения своих проблем. Созданный для решения многих распространенных...
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
0
1
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Одно простое ускорение примерно в 3 раза состоит в том, чтобы подмножить minute_prices data.table, чтобы включить только те строки, которые являются кумулятивным минимумом/максимумом за текущий час (минус 1 секунда, так как соединение datetime > datetime):

dtM <- copy(minute_prices)
dtH <- copy(hourly_prices)

system.time({
  dtH[(Direction == 1),Location := dtM[dtM[, low == cummin(low), as.integer(datetime - 1)%/%3600L][[2]]][.SD, on = .(datetime > datetime, low <= Target_price),mult = "first",x.Position]]
  dtH[(Direction == -1),Location := dtM[dtM[, high == cummax(high), as.integer(datetime - 1)%/%3600L][[2]]][.SD, on = .(datetime > datetime, high >= Target_price),mult = "first",x.Position]]
})
#>    user  system elapsed 
#>    6.77    0.01    6.81

system.time({
  hourly_prices[(Direction == 1),Location := minute_prices[.SD, on = .(datetime > datetime, low <= Target_price),mult = "first",x.Position]]
  hourly_prices[(Direction == -1),Location := minute_prices[.SD, on = .(datetime > datetime, high >= Target_price),mult = "first",x.Position]]
})
#>    user  system elapsed 
#>   22.97    0.00   23.04

identical(dtH, hourly_prices)
#> [1] TRUE

Другие вопросы по теме