Быстрое соединение 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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Одно простое ускорение примерно в 3 раза состоит в том, чтобы подмножить minute_pricesdata.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

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