# Подключение необходимых библиотек
library(httr)
library(jsonlite)
library(tseries)
library(dplyr)
library(zoo)
library(future.apply)
library(progressr)  # Добавляем библиотеку для прогресс-бара

# Установка планировщика для параллельных вычислений
plan(multisession)  # Используем все доступные ядра

# Активация прогресс-баров
handlers(global = TRUE)
handlers("progress")

# URL для получения информации о бессрочных фьючерсах
exchange_info_url <- "https://fapi.binance.com/fapi/v1/exchangeInfo"

# Функция для получения списка символов бессрочных фьючерсных контрактов
get_symbols <- function() {
  tryCatch({
    response <- GET(exchange_info_url)
    
    if (response$status_code != 200) {
      stop("Ошибка получения списка символов: статус код ", response$status_code)
    }
    
    data <- fromJSON(content(response, "text", encoding = "UTF-8"))
    
    perpetual_symbols <- as.data.frame(data$symbols) %>%
      filter(contractType == "PERPETUAL" & quoteAsset == "USDT") %>%
      select(symbol) %>%
      unlist()
    
    return(perpetual_symbols)
  }, error = function(e) {
    message("Не удалось получить символы: ", e)
    return(NULL)
  })
}

# Функция для получения данных за последние 10 дней (High, Low, Close) по символу
get_10_day_data <- function(symbol) {
  tryCatch({
    base_url <- "https://fapi.binance.com/fapi/v1/klines"
    query_params <- list(symbol = symbol, interval = "1d", limit = 10)
    
    response <- GET(base_url, query = query_params)
    
    if (response$status_code != 200) {
      stop("Ошибка получения данных для символа ", symbol, ": статус код ", response$status_code)
    }
    
    data <- fromJSON(content(response, "text", encoding = "UTF-8"))
    
    daily_data <- data.frame(
      Open = as.numeric(data[,2]),
      High = as.numeric(data[,3]),
      Low = as.numeric(data[,4]),
      Close = as.numeric(data[,5]),
      Volume = as.numeric(data[,8])  # Добавляем объём
    )
    
    return(daily_data)
  }, error = function(e) {
    message("Не удалось получить данные для символа ", symbol, ": ", e)
    return(NULL)
  })
}

# Функция для вычисления дневного ренджа в процентах
calculate_daily_range <- function(day_data) {
  open_price <- day_data["Open"]
  close_price <- day_data["Close"]
  high_price <- day_data["High"]
  low_price <- day_data["Low"]
  
  if (is.na(open_price) || is.na(close_price) || is.na(high_price) || is.na(low_price)) {
    return(NA)
  }
  
  if (close_price > open_price) {
    range_percent <- ((high_price - low_price) / low_price) * 100
  } else {
    range_percent <- ((high_price - low_price) / high_price) * 100
  }
  
  return(round(range_percent, 2))
}

# Функция для вычисления волатильности за 10 дней
calculate_10_day_volatility <- function(daily_data) {
  daily_ranges <- apply(daily_data, 1, calculate_daily_range)
  avg_volatility <- mean(daily_ranges, na.rm = TRUE)
  
  return(round(avg_volatility, 2))
}

# Функция для получения исторических данных по символу
get_historical_data <- function(symbol, interval = "1m") {
  tryCatch({
    base_url <- "https://fapi.binance.com/fapi/v1/klines"
    query_params <- list(symbol = symbol, interval = interval, limit = 500)
    
    response <- GET(base_url, query = query_params)
    
    if (response$status_code != 200) {
      stop("Ошибка получения данных для символа ", symbol, ": статус код ", response$status_code)
    }
    
    data <- fromJSON(content(response, "text", encoding = "UTF-8"))
    
    close_prices <- as.numeric(data[,5])
    return(close_prices)
  }, error = function(e) {
    message("Не удалось получить данные для символа ", symbol, ": ", e)
    return(NULL)
  })
}

# Основная функция для получения данных, проверки стационарности и вывода результата
run_stationarity_check <- function(interval) {
  symbols <- get_symbols()
  
  if (is.null(symbols)) {
    message("Не удалось получить список символов. Завершение работы.")
    return(NULL)
  }
  
  # Параллельная обработка символов с прогресс-баром
  progressor <- progressor(along = symbols)  # Инициализация прогресс-бара
  
  results <- future_lapply(symbols, function(symbol) {
    progressor()  # Обновляем прогресс-бар на каждой итерации
    close_prices <- get_historical_data(symbol, interval)
    daily_data <- get_10_day_data(symbol)
    
    if (!is.null(close_prices) && length(close_prices) > 0 && !is.null(daily_data)) {
      consecutive_bars <- check_consecutive_stationarity(close_prices)
      daily_range <- calculate_daily_range(daily_data[10, ])  # Волатильность за последний день
      ten_day_volatility <- calculate_10_day_volatility(daily_data)  # Волатильность за 10 дней
      
      indicators <- check_indicators(close_prices)  # Проверка индикаторов
      
      if (consecutive_bars > 0) {
        return(data.frame(
          Symbol = symbol, 
          Stat_Bars = consecutive_bars, 
          DR = daily_range,
          `10DR` = ten_day_volatility,
          BB = indicators$BB,
          Zs = indicators$Zs,
          Volume = round(daily_data[10, "Volume"] / 1e6, 2)  # Округляем объём до миллионов
        ))
      }
    }
    return(NULL)
  }) %>%
    bind_rows() %>%
    arrange(desc(Stat_Bars)) %>%
    select(-DR) %>%
    rename(DR = High)

  # Вывод времени отчета
  report_time <- format(Sys.time(), "%Y-%m-%d %H:%M:%S")
  print(paste("Отчёт для таймфрейма", interval, "сформирован:", report_time))
  print(results)
  
  return(results)
}

# Функция для сводного отчета по нескольким таймфреймам
run_summary <- function(result_1m, result_5m, result_1h) {
  # Объединение результатов
  all_results <- bind_rows(
    result_1m %>% mutate(Timeframe = "1m"),
    result_5m %>% mutate(Timeframe = "5m"),
    result_1h %>% mutate(Timeframe = "1h")
  )
  
  # Сводный отчёт: тикеры, которые встречаются минимум в двух таймфреймах
  summary_result <- all_results %>%
    group_by(Symbol) %>%
    summarise(Count = n(), Volume = first(Volume)) %>%
    filter(Count >= 2) %>%
    arrange(desc(Volume)) %>%
    slice(1:30)

  # Вывод сводного отчёта
  report_time <- format(Sys.time(), "%Y-%m-%d %H:%M:%S")
  print(paste("Сводный отчёт сформирован:", report_time))
  print(summary_result)
  
  return(summary_result)
}

# Запуск основной функции для разных таймфреймов
result_1m <- run_stationarity_check("1m")
result_5m <- run_stationarity_check("5m")
result_1h <- run_stationarity_check("1h")

# Запуск сводного отчёта на основе трёх предыдущих результатов
run_summary(result_1m, result_5m, result_1h)