Meu objetivo é detectar tendências de preços de criptomoedas. Para isso, estou obtendo dados de preços OHLC para múltiplas moedas versus vários símbolos de cotação (por exemplo, velas para Bitcoin/USD, Bitcoin/EUR, Litecoin/USD etc.). Para realizar o cálculo de tendências utilizo o indicador Supertrend . Eu tenho as 2 tabelas a seguir:
-- This is where price candles AKA OHLC data gets stored. Interval can be '1h', '4h', '1d', etc.
CREATE TABLE ohlc (
id integer DEFAULT nextval('ohlc_id_seq'::regclass) PRIMARY KEY,
open numeric(65,30) NOT NULL,
high numeric(65,30) NOT NULL,
low numeric(65,30) NOT NULL,
close numeric(65,30) NOT NULL,
coinid character varying(255) NOT NULL REFERENCES coin(id) ON DELETE RESTRICT ON UPDATE CASCADE,
closetime timestamp(3) without time zone NOT NULL,
quotesymbol text NOT NULL,
interval text NOT NULL
);
-- This is a caching table that gets automatically populated by a stored procedure that runs AFTER every ohlc insert. "trend" can be 'UP' or 'DOWN'.
CREATE TABLE supertrend (
id integer DEFAULT nextval('supertrend_id_seq'::regclass) PRIMARY KEY,
coinid character varying(255) NOT NULL REFERENCES coin(id) ON DELETE RESTRICT ON UPDATE CASCADE,
quotesymbol text NOT NULL,
date timestamp(3) without time zone NOT NULL,
trend text NOT NULL,
interval text NOT NULL
);
Dados de amostra para a tabela de supertendências:
coinid | símbolo de citação | data | tendência | intervalo |
---|---|---|---|---|
'Bitcoin' | 'USD' | '2024-04-18 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'USD' | '2024-04-17 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'USD' | '2024-04-16 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'USD' | '2024-04-15 00:00:00' | 'ABAIXO' | '1d' |
'Bitcoin' | 'EUR' | '2024-04-18 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'EUR' | '2024-04-17 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'EUR' | '2024-04-16 00:00:00' | 'ABAIXO' | '1d' |
'Bitcoin' | 'EUR' | '2024-04-15 00:00:00' | 'ABAIXO' | '1d' |
'Bitcoin' | 'CNY' | '2024-04-18 00:00:00' | 'ABAIXO' | '1d' |
'Bitcoin' | 'CNY' | '2024-04-17 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'CNY' | '2024-04-16 00:00:00' | 'ACIMA' | '1d' |
'Bitcoin' | 'CNY' | '2024-04-15 00:00:00' | 'ACIMA' | '1d' |
'Litecoin' | 'USD' | '2024-04-18 00:00:00' | 'ABAIXO' | '1d' |
'Litecoin' | 'USD' | '2024-04-17 00:00:00' | 'ACIMA' | '1d' |
'Litecoin' | 'USD' | '2024-04-16 00:00:00' | 'ABAIXO' | '1d' |
'Litecoin' | 'USD' | '2024-04-15 00:00:00' | 'ABAIXO' | '1d' |
'Bitcoin' | 'USD' | '2024-04-18 00:00:00' | 'ACIMA' | '4h' |
'Bitcoin' | 'USD' | '2024-04-17 20:00:00' | 'ACIMA' | '4h' |
'Bitcoin' | 'USD' | '2024-04-17 16:00:00' | 'ABAIXO' | '4h' |
Digamos que eu queira consultar a ORDER BY date DESC
tendência mais recente () para cada coinid/quotesymbol com intervalo = '1d' (1 dia). Ou, em outras palavras WHERE interval = '1d' GROUP BY coinid, quotesymbol
, quero também saber a tendência da tendência, por quantos períodos essa tendência já é a mesma.
Dados os dados da tabela de supertendências do exemplo acima, meu resultado deve ser semelhante a:
coinid | símbolo de citação | última tendência | tendência_streak |
---|---|---|---|
'Bitcoin' | 'USD' | 'ACIMA' | 3 |
'Bitcoin' | 'EUR' | 'ACIMA' | 2 |
'Bitcoin' | 'CNY' | 'ABAIXO' | 1 |
'Litecoin' | 'USD' | 'ABAIXO' | 1 |
Para esclarecer o resultado acima: 'Bitcoin', 'usd' está 'UP' por 3 períodos, porque a tendência para Bitcoin/USD foi de alta em 18 de abril, 17 de abril e 16 de abril. E 'DOWN' em 15 de abril, veja o exemplo tabela de supertendências.
Além disso, gostaria de saber a supertendência agregada sobre todos os símbolos de cotação (via função de modo). Esse resultado deve ficar assim:
coinid | última tendência | tendência_streak |
---|---|---|
'Bitcoin' | 'ACIMA' | 2 |
'Litecoin' | 'ABAIXO' | 1 |
Para esclarecer o resultado acima: A tendência mais recente do Bitcoin/USD é 'UP, Bitcoin/EUR é 'EUR' é 'UP' e Bitcoin/CNY é 'DOWN'. A função mode pega ('UP', 'UP', 'DOWN') e retorna o valor que ocorre mais frequentemente ('UP').
Como posso consultar esses dados de maneira eficiente, considerando que a tabela de supertendências tem milhões ou bilhões de linhas?
Eu estava pensando em uma visão materializada, mas os intervalos mais baixos possíveis para essas supertendências são de 1 minuto e podem ser escritos em momentos distintos, de modo que pode ser uma taxa de atualização necessária muito alta.
Estou tentando evitar o uso de uma solução de cache separada como o Redis para manter simples a quantidade de arquitetura/ambientes necessários, mas acho que isso poderia ser uma opção especialmente para contadores.
Você pode usar
ROW_NUMBER
para determinar o último valor e, em seguida, usar aGROUP BY
para obter sua contagem. então, na próxima etapa, você poderá usar row_number novamente para determinar a tendência com a contagem mais alta.a função da janela
ROW_NUMBER()
faz exatamente o que seu nome diz: fornece um número de linha para cada linha. Com uma função de janela, você consegue agrupar linhas virtualmente e fornecer um row_number para cada grupo, para que você possa ter vários 1 em seu conjunto de resultados. no nosso caso, queremos a última linha de cada grupo, então usamos como ordemDESC
A
LAG
função de janela em um grupo para o valor anterior, é frequentemente usada como aqui para comparar o valor atual com seu antecessor e detectar alterações.mais sobre a função da janela pode estar no manual
Você pode adicionar à
WHERE
cláusula os coinids que deseja mostrar.Como
WHERE rn = 1 AND "coinid" = 'bitcoin'
A segunda consulta é um pouco mais simples, pois primeiro você detecta as alterações em cada "coinid", "quotesymbolo" e "tend".
A função Window sum então cria um grupo, já que você só está interessado no último, então nos preocupamos apenas com rn =m 1.
Seu resultado esperado me confundiu, mas depois de construir sua consulta vi seu erro
violino