MS SQL - данные диаграммы - сворачивание данных - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть некоторые данные обмена из Bitmex, которые я получаю через API и WebSocket и сохраняю в базе данных SQL. Я создал таблицу под названием Свечи. Я создал столбцы из XML для того, что мне нужно. Bitmex может предоставлять только данные свечей за 1 мин, 5 мин, 1 час и 1 день.

Мне нужно как можно быстрее свернуть эти данные в разные временные рамки для моих разных торговых алгоритмов.

Сначала я начал писать функцию свертывания свечей в своей IDE, но как Вы можете представить себе количество данных, это будет длиться вечно, поскольку исходные данные относятся к 2015 году. Самая быстрая обработка, которую я мог бы выполнить, - 10 новых свечей в секунду.

Затем я немного прочитал и здесь, в StackOverFlow, рекомендуется создать хранимую процедуру в базе данных MS SQL. Я должен быть администратором, мои SQL знания по сравнению с большинством здесь очень ограничены, поэтому я выложил все это здесь для некоторого совета.

5 минут в качестве источника, имеет 484949 записей для свертывания. 1 час в качестве источника, имеет 40327 записей для свертывания.

Снимок экрана журнала, иллюстрирующий время, необходимое для свертывания каждого требуемого периода времени

Для свертывания требуется около 57 минут данные от 5 минут свечи в 15 минут. Требуется около 47 минут, чтобы свернуть данные из 5 минут свечей в 30 минут. Требуется около 7 минут, чтобы свернуть данные из 1-часовых свечей в 2-часовой. Требуется приблизительно 4 минуты, чтобы свернуть данные от 1-часовых свечей в 4-часовой. Требуется приблизительно 3 минуты, чтобы свернуть данные от 1-часовых свечей до 6-часового. Требуется около 2 минут, чтобы свернуть данные из 1-часовых свечей в 12-часовой.

Создайте свечу и хранимую процедуру ниже:

USE CryptoSwingTradeZ
create table Candles (
    rID BIGINT PRIMARY KEY IDENTITY,
    exchange varchar(50),
    symbol varchar(20),
    interval varchar(20),
    timestampHuman_utc varchar(50),
    timestamp_utc Decimal(30,0),
    price_open Decimal(30,8),
    price_close Decimal(30,8),
    price_high Decimal(30,8),
    price_low Decimal(30,8),
    volume Decimal(30,8)
);

CREATE INDEX idx_interval ON Candles (interval);
CREATE INDEX idx_timestampHuman_utc ON Candles (timestampHuman_utc);
CREATE INDEX idx_timestamp_utc ON Candles (timestamp_utc);
CREATE INDEX idx_interval_timestamp_utc ON Candles (interval,timestamp_utc);
CREATE INDEX idx_exchange_interval_timestamp_utc ON Candles (exchange,interval,timestamp_utc);
GO
ALTER PROCEDURE dbo.spRollUpData 
    @desired_interval nvarchar(5),
    @delete_source bit
AS

--DROP 
--CREATE 
--ALTER

DECLARE @exchange nvarchar(30) = 'BITMEX';
DECLARE @symbol nvarchar(10) = 'XBTUSD';

DECLARE @source_interval nvarchar(5); 
DECLARE @interval_n int = 0;
DECLARE @interval_off_set int = 0;

DECLARE @timestamp_utc_source_start int;
DECLARE @timestamp_utc_source_end int;
DECLARE @timestamp_utc_range_start int;
DECLARE @timestamp_utc_range_end int;
DECLARE @Bitmex_utc_start int;

IF @delete_source = 1
    DELETE FROM Candles WHERE interval = @desired_interval; --Use this if you want rebuild from scratch.

IF @desired_interval = '15m'
    BEGIN
        SET @Bitmex_utc_start = 1443184500; 
        SET @source_interval = '5m'
        SET @interval_n = 10;
        SET @interval_off_set = @interval_n;    
    END;
ELSE IF @desired_interval = '30m'
    BEGIN
        SET @Bitmex_utc_start = 1443184500; 
        SET @source_interval = '5m'
        SET @interval_n = 20;
        SET @interval_off_set = @interval_n;        
    END;
ELSE IF @desired_interval = '2h'
    BEGIN
        SET @Bitmex_utc_start = 1443189600; 
        SET @source_interval = '1h' 
        SET @interval_n = 2;
        SET @interval_off_set = 60*(@interval_n);
    END;
ELSE IF @desired_interval = '4h'
    BEGIN
        SET @Bitmex_utc_start = 1443193200; 
        SET @source_interval = '1h'
        SET @interval_n = 4;
        SET @interval_off_set = 60*(@interval_n);
    END;
ELSE IF @desired_interval = '6h'
    BEGIN
        SET @Bitmex_utc_start = 1443186000; 
        SET @source_interval = '1h'
        SET @interval_n = 6;
        SET @interval_off_set = 60*(@interval_n);
    END;
ELSE IF @desired_interval = '12h'
    BEGIN
        SET @Bitmex_utc_start = 1443186000; 
        SET @source_interval = '1h'
        SET @interval_n = 12;
        SET @interval_off_set = 60*(@interval_n);       
    END;
ELSE
    BEGIN
        PRINT 'spRollUpData - Not coded yet for ' + @desired_interval; 
        RETURN --exit immediately
    END;

--Get the min and max of the timestamp_utc from the source interval
SELECT @timestamp_utc_source_start = ISNULL(min(timestamp_utc),0),
       @timestamp_utc_source_end = ISNULL(MAX(timestamp_utc),0)                
  FROM Candles 
 WHERE interval = @source_interval;

--Get the max timestamp_utc from the desired interval   
SELECT @timestamp_utc_range_start = ISNULL(MAX(timestamp_utc),0)       
  FROM Candles 
 WHERE interval = @desired_interval;

--This is to check that the source data to roll up from is available
if @timestamp_utc_source_start = 0
    BEGIN
        PRINT 'spRollUpData - Cannot role up data without SOURCE DATA!'
        RETURN
    END;

--Range start should be the desired last entry if it exists else use @Bitmex_utc_start above
if @timestamp_utc_range_start = 0
    SET @timestamp_utc_range_start = @Bitmex_utc_start;

WHILE @timestamp_utc_range_start <= @timestamp_utc_source_end
BEGIN   
    INSERT INTO Candles 
        SELECT @exchange exchange,
               @symbol symbol,
               @desired_interval interval,
               CandleOpenData.timestampHuman_utc timestampHuman_utc,
               CandleOpenData.timestamp_utc timestamp_utc,
               CandleOpenData.price_open price_open,
               CandleCloseData.price_close price_close,
               CandleSum.price_high price_high,
               CandleSum.price_low price_low,
               CandleSum.volume volume
            FROM  
         (SELECT timestampHuman_utc,timestamp_utc,price_open 
            FROM Candles 
           WHERE exchange = @exchange 
             and interval = @source_interval 
             and timestamp_utc = @timestamp_utc_range_start ) CandleOpenData,
         (SELECT 
            price_close 
            FROM Candles 
           WHERE exchange = @exchange 
             and interval = @source_interval 
             and timestamp_utc = @timestamp_utc_range_start + (60*@interval_off_set) ) CandleCloseData
             ,
         (SELECT    
            max(price_high) price_high, 
            min(price_low) price_low, 
            sum(volume) volume
            FROM Candles 
           WHERE exchange = @exchange 
             and interval = @source_interval 
             and timestamp_utc >= @timestamp_utc_range_start
             and timestamp_utc <= @timestamp_utc_range_start + (60*@interval_off_set) ) CandleSum
    WHERE NOT EXISTS (
              SELECT timestamp_utc 
                FROM Candles 
               WHERE exchange = 'Bitmex' 
                 and symbol = @symbol
                 and interval = @desired_interval 
                 and timestamp_utc = @timestamp_utc_range_start
                 and CandleOpenData.timestamp_utc = timestamp_utc
            );

    SET @timestamp_utc_range_start = @timestamp_utc_range_start + (60*@interval_off_set);
END
GO

Таким образом, хранимая процедура будет использовать время запуска источника Я обеспечу это и закончу, когда все петли будут сделаны. Постепенно я получаю данные, необходимые для создания свечных данных, а затем вставляю.

Пример снимка экрана

На снимке экрана в качестве примера при запуске это через хранимую процедуру, это создаст 6 х 15 м свечи. Если запрос SELECT вернет менее 3 свечей за последний l oop, он проигнорирует его, поскольку он все еще не завершен.

Как я могу свернуть данные быстрее? :)

...