Series armazena o histórico associado aos candles. Às vezes, porém, você quer decidir quais valores o programa reúne, em que ordem e quando os exclui. Para isso, pode usar um array.

O que um array armazena?

Um array é formado por elementos em sequência. Cada elemento tem um índice; o primeiro índice é zero.

Um array armazena elementos do mesmo tipo. Você pode ter, por exemplo, um array de números ou de textos, mas não colocamos texto em um array numérico. Mesmo tipo não significa mesmo valor: 100, 103 e 101 são números diferentes no mesmo array.

Se 100, 103 e 101 forem inseridos nessa ordem, o elemento de índice 0 será 100; o de índice 1, 103; o de índice 2, 101. Aqui, o índice identifica uma posição de armazenamento. Ele não representa automaticamente um valor de candles anteriores.

close[1] é o fechamento do candle anterior. array.get(prices, 1) é o segundo elemento do array prices. A idade do elemento depende de como você preencheu o array.

O namespace array

array.new_float(0) cria um array numérico inicialmente vazio. O zero é a quantidade inicial de elementos, não um preço inicial.

OperaçãoFunção
array.push(prices, close)Acrescenta um elemento ao fim do array
array.size(prices)Informa a quantidade de elementos
array.shift(prices)Remove e devolve o primeiro elemento
array.get(prices, 0)Lê o primeiro elemento
array.avg(prices)Calcula a média dos números armazenados

O índice de array.get deve apontar para um elemento existente. Em um array de três elementos, 0, 1 e 2 são válidos; 3 já não é.

Armazene cinco preços recentes

Crie o arquivo recent_prices.py:

"""
@pyne edge
"""
from pynecore import Persistent
from pynecore.lib import array, close, color, plot, script, ta


@script.indicator("Recent Prices", overlay=True)
def main():
    prices: Persistent[list[float]] = array.new_float(0)
    array.push(prices, close)
    if array.size(prices) > 5:
        array.shift(prices)
    stored_average = array.avg(prices)
    full_average = ta.sma(close, 5)
    plot(stored_average, "Stored average", color=color.blue, linewidth=2)
    plot(full_average, "SMA 5", color=color.orange)

A anotação list[float] é o tipo de um array numérico. Persistent garante que o array continue existindo no próximo candle. Sua criação não é repetida em todos os candles.

Realizamos as operações pelo namespace array. Não é preciso importar uma biblioteca Python de uso geral nem escrever um literal de lista próprio.

Execute com os dados de demonstração. A linha azul desenha a média dos preços já reunidos. No primeiro candle, há um preço; no segundo, dois; depois, três e quatro. A partir do quinto candle, permanecem cinco elementos.

O gráfico de recent_prices.py mostra a média azul dos preços armazenados e a SMA de cinco em laranja.
Comparamos a média do nosso array com a SMA calculada com a janela completa de cinco elementos.

A ordem de adicionar e remover

No sexto candle, primeiro acrescentamos o sexto fechamento. Nesse momento, o array tem seis elementos. A condição de if é verdadeira, por isso removemos o primeiro, o mais antigo. Quando calculamos a média, restam apenas os cinco fechamentos do segundo ao sexto candle.

Neste programa, o início do array contém o preço preservado mais antigo; o fim contém o mais recente. Portanto, a partir de cinco elementos, array.get(prices, 0) fornece o preço de quatro candles atrás. Ele não corresponde ao preço atual.

Para ler o mais recente, o último índice é array.size(prices) - 1. Como a numeração começa em zero, a quantidade de elementos e o último índice diferem em um.

Janelas parciais e completas

As duas médias desenhadas se comportam de forma diferente no começo. A média do array pode ser calculada com os preços já reunidos, mesmo que ainda sejam no máximo quatro. ta.sma(close, 5) só fornece um valor com uma janela completa de cinco elementos.

A partir do quinto candle, ambas calculam a média dos mesmos cinco fechamentos. Daí em diante, as linhas devem coincidir dentro da precisão da representação numérica.

Por isso, uma média feita com um array não substitui automaticamente a média móvel pronta. Você precisa definir a regra da janela inicial.

Por que limitar o tamanho?

Se você apenas acrescentar um elemento em cada candle, o array crescerá com a extensão dos dados. Ao fim da execução, ele armazenaria todos os fechamentos processados.

Aqui, precisamos dos últimos cinco preços, por isso removemos os mais antigos. Assim, no momento do cálculo, o armazenamento tem no máximo cinco elementos. Em uma tarefa real de coleta, também defina quais dados devem ser preservados e por quanto tempo.

Tente por conta própria

Modifique o programa para preservar três preços no array. Defina também o comprimento da SMA pronta como três. Depois, desenhe o elemento mais antigo preservado no array como uma terceira linha.

Solução do exercício

A condição de remoção:

if array.size(prices) > 3:
    array.shift(prices)

A média pronta e a nova linha:

full_average = ta.sma(close, 3)
oldest_price = array.get(prices, 0)
plot(oldest_price, "Oldest stored price", color=color.gray)

array.push vem antes da leitura em cada candle, por isso o array já tem pelo menos um elemento nesse momento. Depois de chegar a três elementos, o preço mais antigo é o de dois candles atrás.

Anote o conteúdo do array

Preservando três elementos em vez de cinco e usando a sequência de preços 100, 103, 101 e 105, anote o conteúdo do array depois de cada um dos quatro candles. No quarto candle, ele deve conter 103, 101 e 105, nessa ordem.