HTS
HT Code

Manual do HT Code: robôs e indicadores em C# na HTS

Você escreve em C#, a HTS compila e assina, e o robô roda no seu HTS desktop, no backtest ou ao vivo na sua conta. Este é o manual inteiro: do primeiro robô à referência de cada função.

Atualizado em 31/10/2026 · 40 min de leitura

O HT Code aberto na HTS, com o código de um indicador MACD em C# e o gráfico ao lado

O HT Code é onde a sua estratégia vira robô. Você escreve em C#, uma linguagem de programação de verdade, com tipos, classes, listas, funções e bibliotecas próprias, e a HTS cuida do resto: compila, testa no histórico, desenha no gráfico e opera ao vivo na sua conta, com o mesmo código do começo ao fim. Se você já tem um setup que opera na mão, uma planilha que calcula sinais ou um robô escrito em outra plataforma, este é o lugar de trazê-lo.

Por que trazer seus algoritmos para cá

Uma linguagem de verdade, sem amarras de script

C# é a linguagem do .NET, usada em sistemas de banco, jogos e software de mercado no mundo todo. Você organiza a estratégia em classes e funções, guarda estado em listas e dicionários, reaproveita código em bibliotecas suas e escreve a lógica que quiser, do cruzamento de médias ao modelo estatístico.

O mesmo número que você vê no gráfico

São mais de 50 indicadores prontos (médias, bandas, osciladores, tendência, volume, VWAP, Ichimoku, padrões de candle) com a mesma conta do gráfico da HTS. O RSI do seu robô é o RSI da tela, candle a candle: o que você enxerga é o que o robô decide.

Backtest que respeita o candle por dentro

O backtest roda no seu PC, sobre os candles do ativo, com slippage, corretagem, posição máxima e as regras da automação. Se o robô decide no meio do candle, o motor anda dentro de cada candle pela "lupa" de 1 minuto, na ordem provável de máxima e mínima, e confere stop e alvo ponto a ponto. O otimizador testa faixas de parâmetros e faz walk-forward (otimiza num trecho e confere no seguinte), para separar estratégia boa de estratégia ajustada ao passado.

Do teste para a conta sem reescrever nada

O código que passou no backtest é o mesmo que opera ao vivo, no Simulador ou na sua conta real, pelo HTS desktop. Você escolhe o ativo, o tempo gráfico e as regras da automação, liga, e acompanha cada ordem, o resultado do dia e o diário do robô.

Decida no fechamento ou no negócio

O robô pode decidir no fechamento de cada candle ou a cada negócio da bolsa, assim que a condição bater. Ao vivo, ele lê o book, a agressão de compra e venda e os últimos negócios: dá para escrever estratégia de fluxo, não só de candle.

Vários tempos e ativos na mesma estratégia

Um robô de 5 minutos pode confirmar a tendência no gráfico de 60 minutos e olhar o dólar enquanto opera o índice. Basta declarar a série que ele usa.

Robôs e indicadores, na mesma linguagem

Você programa os dois: robôs que operam sozinhos e indicadores que desenham no gráfico. O indicador aparece em "Meus indicadores", com linhas, histogramas, bandas preenchidas, marcas, candles pintados e tabela, e com os parâmetros editáveis como qualquer estudo. Muitas vezes o caminho é esse: primeiro o indicador mostra o sinal no gráfico, depois o mesmo raciocínio vira robô.

Proteção que trabalha por você

Seu robô opera com uma rede de segurança. Stop, alvo e as regras de risco que você escolhe (horário, meta e limite de perda do dia) são vigiados pela plataforma o tempo todo, mesmo se o código falhar. Você foca na estratégia; a disciplina fica garantida.

Comece por aqui

  1. No terminal, abra HT Code (menu Automações). O "+" cria um código novo, em branco. A aba Exemplos, ao lado

do Explorador, tem dezenas de robôs e indicadores prontos para ler e copiar.

  1. Dê um nome, escreva (ou cole) o código e clique em Compilar. Os problemas aparecem sublinhados no texto e na

lista "Problemas".

  1. Robô (código que manda ordem): Backtest roda no histórico, no seu PC. Indicador (código que só desenha):

Rodar desenha no gráfico ao lado.

  1. Para operar de verdade: em Meus robôs (menu Automações) crie uma automação (robô, conta, ativo e tempo gráfico),

escolha as regras e ligue. O robô roda no seu HTS desktop; se o desktop fecha, o robô para e a posição fica.

A categoria do código é automática: quem chama Buy, Sell, ClosePosition, StopLoss ou TakeProfit é robô; quem não chama é indicador; um código sem classe que herde de Robot é biblioteca (código compartilhado, que entra em todos os outros).

Nos exemplos deste manual, um trecho só com comandos roda dentro do OnBarClose; um trecho com campos ou override fica dentro da classe do robô. Todos compilam como estão.

Como um robô é feito

Todo robô é uma classe que herda de Robot. Dentro dela há três partes, sempre nesta ordem de leitura:

ParteO que éExemplo
ParâmetrosValores que você ajusta na tela sem mexer no código, e que o otimizador testa.[Parameter("Período")] public int Periodo = 20;
VariáveisO que o robô guarda entre um candle e outro: indicadores, contadores, o preço de entrada.private Sma media = null!;
EventosOs momentos em que o motor chama o seu código: o início, cada candle, cada negócio, o fim.public override void OnBarClose() { ... }

Não precisa escrever using: a API do robô (HTS.Robots e HTS.Robots.Indicators) e o básico do C# (System, System.Linq, System.Collections.Generic) já vêm prontos em todo código. O código começa direto na classe.

O esqueleto de um robô

Um robô completo de cruzamento de preço com a média, com stop e alvo, cabe em poucas linhas:

public class MeuRobo : Robot{    [Parameter("Período", Min = 2, Max = 200)] public int Periodo = 20;    private Sma media = null!;    public override void OnStart()        // uma vez, antes do primeiro candle: crie os indicadores aqui    {        media = new Sma(Periodo);    }    public override void OnBarClose()   // a cada candle FECHADO: é aqui que o robô decide    {        media.Update(Current);        if (!media.IsReady) return;        Plot("Média", media.Value);        if (Position.IsFlat && Current.Close > media.Value) { Buy(1); StopLoss(150); TakeProfit(300); }        else if (Position.IsLong && Current.Close < media.Value) ClosePosition();    }    public override void OnStop() { }   // uma vez, no fim (ou quando a automação é desligada)}

Linha a linha:

  • [Parameter("Período")] transforma Periodo num campo da tela, com mínimo e máximo.
  • private Sma media é a variável que guarda a média móvel entre um candle e outro.
  • OnStart cria a média uma vez só; OnBarClose a avança com o candle que fechou (Current).
  • IsReady diz que a média já tem candles suficientes; antes disso, o robô espera.
  • Plot desenha a média no gráfico do backtest; Buy(1) compra um contrato a mercado, e StopLoss(150) e

TakeProfit(300) põem stop e alvo a 150 e 300 pontos do preço médio.

Como o robô roda

O motor entrega o histórico ao robô candle a candle, do mais antigo ao mais recente, e chama OnBarClose uma vez para cada candle fechado. Quando o histórico acaba, ao vivo, o robô continua do mesmo jeito: cada candle que fecha é mais uma chamada. Por isso o mesmo código serve para o backtest e para a conta.

Dentro de cada chamada, o robô enxerga o candle que acabou de fechar e todo o passado até ele, nunca o futuro:

No códigoO que é
CurrentO candle que acabou de fechar (abertura, máxima, mínima, fechamento, volume).
Closes[0], Closes[1]O fechamento de agora e o do candle anterior (como Close[1] em outras plataformas).
media.Value, media[1]O valor do indicador agora e um candle atrás.
PositionA posição de agora: zerada, comprada ou vendida, com o preço médio.
Now, TodayO horário do candle (em Brasília) e o dia do pregão.

Para decidir no meio do candle, implemente também OnTick: ao vivo, ele roda a cada negócio da bolsa; no backtest, em cada ponto da lupa de 1 minuto. A mesma chamada pode mandar várias ordens a mercado (até 20); elas saem em sequência, cada uma conferida pela posição que as anteriores deixam.

O que o motor faz por você

  • Stop e alvo de verdade: o motor confere o toque a cada negócio (e, no backtest, em cada ponto de dentro do

candle), mesmo que o seu código não esteja rodando naquele instante.

  • Sem mão dobrada: ao vivo, a entrada pedida numa chamada seguinte espera a anterior chegar à posição; sair e

reduzir passam sempre.

  • Regras da automação acima do código: horário, leilão, meta e stop do dia, perdas seguidas, número de operações e

posição máxima valem sempre.

  • Código isolado: o robô não acessa internet, arquivos nem o relógio do PC. Tudo o que ele sabe vem do mercado e

tudo o que ele pede passa pelo motor, por isso o backtest e a conta se comportam igual.

Fim do pregão. A última barra do dia chega com o mercado fechado, e nada executa nela. A entrada pedida é recusada (AoOrdemRecusada, FORA_DO_HORARIO, "O pregão de 29/10 já fechou..."). A saída fica guardada e vai ao mercado na abertura do pregão seguinte, uma vez só, nunca maior que a posição daquele momento; recusada de novo com o mercado fechado, o motor manda outra vez enquanto houver posição, com a espera crescendo de 5 s a 30 s. O Zerar guardado não fecha uma posição que virou de lado durante a noite. O mesmo vale para o que o robô pedir depois do fechamento e para a zeragem pela regra. O toque do stop ou do alvo com o mercado fechado não sai: a posição dorme com a proteção, e na abertura quem decide é o preço. Se ele continua além do stop ou do alvo, sai por ele; se voltou, não sai e a proteção segue. Um negócio isolado de noite não é toque. Pendente pedida com o pregão fechado é recusada. Ao vivo, a penúltima barra pode fechar já depois do fim do pregão, no primeiro negócio do leilão de fechamento, e segue as mesmas regras; no backtest ela executa normalmente. Se o mercado for dado por fechado e continuar negociando (mais de 10 min depois, com 2 negócios em até 60 s), o motor volta a operar no mesmo dia. O backtest faz igual: a entrada na última barra é recusada e a saída executa na abertura seguinte, com o escorregamento; se a abertura cruzar o stop ou o alvo, sai por ele. Com "Zerar no fim do pregão" ligado, o backtest zera no fechamento dessa barra, como sempre. Não vale no tempo D, cuja barra só fecha com o primeiro negócio do dia seguinte, nem em ativo de 24 h, que não tem fim de pregão. Se o HTS for fechado antes da abertura, a saída guardada não vai: confira a posição. Num HTS desktop anterior ao host de robôs 1.2.0, a última barra só chega com o primeiro negócio do dia seguinte: atualize o HTS.

Posição atrasada. Se a posição demorar mais de 30 s a mostrar uma execução, o stop, o Zerar e a zeragem pela regra não vendem de novo o que já foi vendido: a saída não sai até a posição mostrar, ou por até 2 min, com um aviso no diário. Se a posição atrasar mais que isso (cerca de 2 min e meio no total), a saída pode vender de novo: confira a posição. A entrada em lote e a stop ou limitada do robô que reduz voltam quando a posição mostrar a entrada.

Os eventos do robô

Início do robô

OnStart()

Uma vez, antes do primeiro candle. É onde se criam os indicadores.

private Ema rapida = null!;public override void OnStart() { rapida = new Ema(9); }

Fechamento do candle

OnBarClose()

A cada candle FECHADO. Obrigatório: é onde o robô decide.

public override void OnBarClose(){    if (Position.IsFlat && Current.IsBullish) Buy(1);}

A cada negócio

OnTick(Tick tick)

A cada negócio, para entrar no meio do candle assim que a condição bater. No backtest, o motor anda dentro de cada candle pela "lupa" de 1m (abertura, máxima e mínima na ordem provável, fechamento) e chama aqui em cada ponto; a lupa cobre até 50 mil minutos, e antes disso cada candle vira 4 pontos (o backtest avisa).

public override void OnTick(Tick tick){    if (Position.IsFlat && CurrentDay is Bar dia && tick.Price > dia.High) Buy(1);}

A cada mudança do book

OnBook(Book book)

A cada mudança do book. Só ao vivo (não há book histórico no backtest).

public override void OnBook(Book book){    if (book.BestBid is BookLevel compra && book.BestAsk is BookLevel venda && compra.Quantity > 3 * venda.Quantity)        Log("comprador pesado no topo do book");}

Fim do robô

OnStop()

Uma vez, no fim do backtest ou quando a automação é desligada.

public override void OnStop() { Log($"Fim: {Trades.Count} operações"); }

Estado do pregão

Session

O estado do pregão do ativo: aberto, em leilão ou fechado (no backtest, desconhecido).

if (Session == SessionState.Auction) return; // não decide em leilão

Ordens, posição, stop e alvo

Compra e venda a mercado

Buy(n)Sell(n)

Ordem a mercado de n contratos. No backtest executa no fechamento do candle (ou no ponto da lupa, em OnTick) com o slippage configurado; ao vivo, vai para a sua conta.

if (Position.IsFlat && Current.Close > Current.Open) Buy(1);

Zerar a posição

ClosePosition()

Zera a posição que existe, a mercado.

if (Now.HHMM >= 1740 && !Position.IsFlat) ClosePosition();

Posição

Position

A posição líquida: quantidade com sinal e preço médio, com IsFlat, IsLong, IsShort, Contracts e OpenProfit(preco, SymbolInfo) (o resultado aberto em reais).

if (Position.IsLong && Position.OpenProfit(Current.Close, SymbolInfo) > 300) ClosePosition();

Stop e alvo em pontos

StopLoss(pontos)TakeProfit(pontos)

Stop e alvo a essa distância do preço médio; chamar de novo substitui. Sem posição e sem ordem no candle, são recusados.

if (Position.IsFlat) { Buy(1); StopLoss(150); TakeProfit(300); }

Cancelar stop e alvo

CancelStops()

Remove o stop e o alvo do motor.

if (Position.IsFlat) CancelStops();

Dados do ativo

SymbolInfo

O ativo do robô: tick, valor do ponto e moeda.

var reaisPorPonto = SymbolInfo.PointValue * Position.Contracts;Log($"{SymbolInfo.Symbol}: tick {SymbolInfo.TickSize}, R$ {reaisPorPonto} por ponto na posição");

Ordens pendentes, stop móvel e eventos da ordem

Compra limitada e venda limitada

BuyLimit(qtd, preco)SellLimit(qtd, preco)

Ordem limitada. Aceitam nome (até 40 caracteres) e comentario (até 80). Repetir o nome substitui a pendente anterior; sem nome, o motor dá um (limite-1...). Até 20 pendentes por robô.

if (Position.IsFlat) BuyLimit(1, Current.Low - 50, "pullback");

Stop de compra e stop de venda

BuyStop(qtd, gatilho)SellStop(qtd, gatilho)

Ordem stop: vira a mercado quando o preço toca o gatilho.

if (Position.IsFlat && CurrentDay is Bar dia) BuyStop(1, dia.High + 5, "rompe-maxima");

Stop limitado de compra e de venda

BuyStopLimit(qtd, gatilho, limite)SellStopLimit(...)

No gatilho, vira limitada no preço limite. Só no Simulador.

if (Position.IsFlat) BuyStopLimit(1, Current.High + 10, Current.High + 20, "stop-limite");

Cancelar e alterar pendentes

Cancel(nome)CancelAll()Modify(nome, preco)

Mexem nas pendentes; PendingOrders lista as de agora.

if (PendingOrders.Count > 0 && Now.HHMM >= 1700) CancelAll();if (!Modify("pullback", Current.Low - 30)) Log("não havia pendente com esse nome");

Pendente que só reduz (entrada com alvo)

Buy(1); SellLimit(1, alvo) é entrada com alvo; se a posição zerar, a pendente cai. Pendentes valem no dia: caem na virada, no teto e no encerramento. No backtest são conferidas a partir do candle seguinte (limite sem slippage, stop com slippage, gap a favor ou contra na abertura).

if (Position.IsFlat) { Buy(1); SellLimit(1, Current.Close + 300, "alvo"); }

Saída parcial e virada de mão

ClosePartial(n)Reverse()

Zera parte da posição ou vira a mão.

if (Position.Contracts >= 2 && Position.OpenProfit(Current.Close, SymbolInfo) > 200) ClosePartial(1);

Stop e alvo num preço

StopLossAt(preco)TakeProfitAt(preco)

Stop e alvo num preço, em vez de distância.

if (Position.IsLong && PreviousDay is Bar ontem) StopLossAt(ontem.Low);

Stop móvel e break-even

TrailingStop(pontos)BreakEven(gatilho, folga)

Stop móvel e break-even, cuidados pelo motor (não viram ordem na corretora até tocar).

if (Position.IsFlat) { Buy(1); StopLoss(150); TrailingStop(100); BreakEven(120, 10); }

Ordem executada

OnFill(Fill fill)

Uma ordem executou. Dá para pôr stop e alvo ali.

public override void OnFill(Fill fill){    Log($"executou {fill.Side} {fill.Quantity} a {fill.Price:0}");    if (!Position.IsFlat) { StopLoss(150); TakeProfit(300); }}

Ordem recusada ou cancelada

OnOrderRejected(ordem, codigo, mensagem)OnOrderCanceled(ordem, motivo)

A ordem foi recusada ou cancelada. Códigos das pendentes: NOME_INVALIDO, PRECO_INVALIDO, PENDENTES_DEMAIS, STOP_LIMITE_SO_SIMULADOR, SERIE_INDISPONIVEL, SERIE_INVALIDA.

Cada robô envia até 150 ordens por minuto, e cada Modify conta como uma. Acima disso, a entrada e o Modify de uma entrada são recusados com TAXA_EXCEDIDA (a ordem modificada fica como estava). Saídas, cancelamentos e o Modify de um stop ou alvo que só reduz a posição sempre passam.

Na conta real MT5, a saída nunca aumenta a posição na corretora. Se ela tem menos que a carteira do robô, a saída vende só o que há e avisa. Zerada ou do outro lado, a saída é recusada com LIQUIDO_NAO_COBRE: confira a posição. SAIDA_EM_VOO quer dizer que outra saída do mesmo ativo ainda está a caminho. O stop continua valendo e o motor tenta de novo.

public override void OnOrderRejected(PendingOrder order, string code, string message){    Log($"recusada: {code} {message}", LogLevel.Warning);}

Outros tempos, outros ativos e o fluxo

Outro tempo gráfico ou outro ativo

[UsesSeries]CandlesOf

Declare na classe [UsesSeries("15m")] (mesmo ativo, outro tempo) ou [UsesSeries("WDOFUT", "5m")] (outro ativo) e leia com CandlesOf: os candles fechados, o mais antigo primeiro. Tempos: os temporais do gráfico, em minutos (1m a 1439m: 2m, 10m, 45m...), em horas (2h, 3h, 4h...) ou D; "120m" e "2h" são a mesma série. Séries atemporais (Renko, Range...) ainda não. Até 4 séries e 2 ativos extras. No backtest só o mesmo ativo, num tempo múltiplo do teste (num teste atemporal, nenhum), montado como no gráfico: 5m, 15m, 30m e 60m alinhados ao relógio; os outros contando do início do pregão (45m = três de 15m, a partir da abertura). Com o teste num tempo que o banco não guarda (2m, 10m, 45m...), um minuto sem negócio desloca a contagem: a série feita de uma base maior que a do teste (2m pedindo 30m) só sai quando toda barra do teste cabe nos baldes dela; senão fica vazia, com o motivo na recusa.

[UsesSeries("15m")]public class FiltroDe15 : Robot{    public override void OnBarClose()    {        var c15 = CandlesOf("15m");        if (c15.Count > 0 && c15[^1].IsBullish && Position.IsFlat) Buy(1);    }}

Negócios recentes, agressão e ajuste

RecentTicksAggressionSettlement

Só ao vivo: os últimos negócios (até 500), a agressão de compra e venda desde que o robô ligou e o ajuste do dia nos futuros.

if (Aggression.Delta > 500 && Position.IsFlat) Buy(1);if (Settlement is double ajuste && Current.Close < ajuste) Log("abaixo do ajuste");

Regras da automação (a tela, não o código)

Na automação a pessoa escolhe: início, não abrir depois de, zerar às, esperar N minutos da abertura, pausar no leilão, meta do dia, stop diário, perdas seguidas, operações por dia e posição máxima. Quem vigia é o motor. Regra nunca bloqueia saída: zerar, reduzir, stop e alvo passam sempre. Encerrado o dia, só saída até o próximo pregão.

Regras escolhidas na tela

Rules

As regras escolhidas na tela, só para ler.

if (Rules.FlattenAt is int zera && Now.HHMM >= zera - 5) return; // perto de zerar, não entra

Situação do dia

StoppedForDayStopReasonEntriesTodayConsecutiveLosses

O dia já encerrou, por quê, quantas entradas hoje e quantas perdas seguidas.

if (StoppedForDay) { Log($"parado: {StopReason}"); return; }if (EntriesToday >= 3 || ConsecutiveLosses >= 2) return;

Tempo e calendário da B3

Hora e dia do pregão

NowToday

O robô não lê relógio: Now é o momento do evento em Brasília (no candle, o FIM dele; no negócio, a hora dele) e Today é o pregão. Now.HHMM dá 1740 às 17:40.

if (Now.HHMM < 915 || Now.HHMM >= 1730) return;if (Today.Weekday == Weekday.Friday && Now.Hour >= 16) return;

Gráficos atemporais

SecondsPerCandleCurrent.End

Nos gráficos atemporais (Renko, Range, Pontos, Ponto e figura, negócios, volume) a barra não tem duração fixa: SecondsPerCandle é 0. As barras são montadas dos candles de 1 minuto, então a hora tem precisão de minuto: Current.Time é o minuto em que a barra FECHOU (não o começo dela) e Current.End é o fim desse minuto (é ele o Now do fechamento). As que fecham no mesmo minuto ficam 1 segundo uma depois da outra, e a última vai até o fim do minuto. Por isso End - Time não diz quanto a barra levou para se formar; o tempo entre duas barras é a diferença entre os End delas, com precisão de minuto. MinutesSinceOpen conta do minuto em que fechou a primeira barra de hoje. No backtest, a ordem a mercado de uma barra atemporal executa no fechamento do minuto em que ela fechou (o preço de verdade, não o fechamento desenhado do tijolo ou da coluna), e o stop, o alvo e as pendentes são conferidos pelos candles de 1 minuto de dentro dela e pelos que sobram do pregão depois da última barra; o OnTick anda por esses mesmos candles de 1 minuto.

if (SecondsPerCandle == 0 && Candles.Count > 1){    var desdeAAnterior = Current.End - Candles[^2].End; // segundos entre os fechamentos, com precisão de minuto    if (desdeAAnterior < 60 && Current.IsBullish) Log("fechou no mesmo minuto da anterior");}

Os gráficos atemporais recomeçam a cada pregão, no 1º negócio do dia: as barras de um dia saem só dos candles de 1 minuto daquele dia. O Renko e o Renko ATR começam na abertura do 1º candle, o ATR recomeça junto, nenhuma barra atravessa a noite e o gap da abertura não vira tijolo. A barra que ainda estava em formação no fim do dia (Pontos, Range, Ponto e figura, negócios, volume) fecha ali, mais curta; o Renko não tem barra em formação. Ao vivo, ela fecha quando o mercado encerra o pregão. É isso que faz o gráfico, o backtest e o robô ao vivo darem as mesmas barras em todo pregão inteiro, com histórico de qualquer tamanho. O 1º pregão de cada histórico baixado fica de fora, porque pode vir cortado; num ativo novo, com um ou dois pregões de histórico, tudo fica. O backtest atemporal cobre os pregões que o histórico de 1 minuto ainda guarda (uma janela que anda: os mais antigos saem), menos esse 1º.

Isso vale para o tempo gráfico do robô. O indicador Renko que você cria no código com new Renko(...) é outro: ele anda nos candles que recebe, sem recomeçar a cada pregão.

Ao vivo, o Now nunca volta: a barra que chega depois de um negócio mais novo (os tijolos que fecharam no mesmo minuto; a última barra do pregão de um tempo como 45m ou 2h, que só fecha com o primeiro candle do pregão seguinte) fica com a hora desse negócio. A barra de um pregão que já passou entra em Candles e chama o OnBarClose (os indicadores andam nela), mas o motor não confere o stop e o alvo pela faixa dela, e as regras ("zerar às", janela) são as da hora de agora.

Ao vivo, num gráfico atemporal, o stop, o alvo, o stop móvel, o break-even e a MEP/MEN são conferidos só pelos negócios: a mínima e a máxima da barra (no Ponto e figura, a coluna inteira; no Renko, o tijolo) têm preços de antes da entrada e não disparam nada. O negócio que chega enquanto a ordem anterior ainda não voltou é conferido assim que ela volta. Se o feed de negócios cair, a proteção espera o próximo negócio.

Ao vivo, num gráfico de tempo (1m, 5m, 60m, D...), o stop, o alvo, o stop móvel, o break-even e a MEP/MEN são conferidos a cada negócio e também pela mínima e pela máxima da barra que fechou. A faixa da barra pega o toque que chegou enquanto a ordem anterior ainda não tinha voltado e o que o feed de negócios perdeu. Ela só vale para a proteção que já existia quando a barra começou. Se a proteção começar ou mudar no meio da barra (a entrada com stop ou alvo, um stop ou um alvo novo, um passo do stop móvel), o fechamento dela confere só os negócios que chegaram depois disso: a mínima e a máxima de antes não disparam nada nem puxam o stop móvel, e o toque na proteção de antes que chegou com a ordem anterior ainda sem voltar também não conta mais. A MEP/MEN de uma entrada sem stop nem alvo segue pela barra inteira. Na barra seguinte, a faixa inteira volta a valer. No backtest é o mesmo: a ordem a mercado executa no fechamento da barra e o stop dela vale a partir da barra seguinte; com OnTick, a partir do ponto seguinte da lupa.

A entrada pedida no OnBarClose da última barra de um pregão que já passou, quando ela só chega no pregão seguinte (mais de 1 h depois do fim dela), é recusada com FORA_DO_HORARIO e o motivo no diário; a saída passa. Não vale para o gráfico D (o D de ontem sempre fecha com o primeiro negócio de hoje: é o sinal para a abertura, como no backtest) nem para a virada da meia-noite de um mercado de 24 h.

Calendário da B3

B3Calendar

Feriados, vencimentos e dias úteis da B3.

var du = B3Calendar.BusinessDaysToExpiration(SymbolInfo.Symbol, Today);if (du is <= 1) return; // não opera na véspera do vencimento

Dia, dia anterior, semana e mês

CurrentDayPreviousDayCurrentWeekCurrentMonth

Abertura, máxima, mínima, fechamento e volume do período.

if (PreviousDay is Bar ontem && Current.Close > ontem.High && Position.IsFlat) Buy(1);

Minutos desde a abertura

MinutesSinceOpen

Minutos desde o primeiro candle do dia.

if (MinutesSinceOpen is < 15) return; // espera 15 minutos de pregão

Séries e números

Candles como séries

ClosesOpensHighsLowsVolumes

Os candles como séries: [0] é agora, [1] o candle anterior (como close[1]).

if (Closes[0] > Closes[1] && Closes[1] > Closes[2]) Log("três fechamentos subindo");

Média, soma, máxima e outras contas de série

Valem para qualquer série (candles, indicadores, as suas): Average(n), Sum(n), StdDev(n), Highest(n) e Lowest(n) (valor e há quantos candles), Rising(n), Falling(n), Change(n), Percentile(n, p), Correlation(outra, n).

var maior = Highs.Highest(20);if (Current.Close > maior.Value && Volumes[0] > Volumes.Average(20)) Buy(1);

Série própria

new Series()

Uma série sua, um valor por candle (Add).

private readonly Series amplitude = new();public override void OnBarClose(){    amplitude.Add(Current.Range);    if (amplitude.Count >= 10 && Current.Range > 2 * amplitude.Average(10)) Log("candle largo");}

Série de sim ou não

BoolSeries

Série de sim/não: BarsSince() (há quantos candles foi) e ValueWhen(serie).

private readonly BoolSeries subiu = new();public override void OnBarClose(){    subiu.Add(Current.IsBullish);    if (subiu.BarsSince() is > 5) Log("6 candles sem alta");}

Valor inválido (NaN)

Na(x)Nz(x, padrao)

O aquecimento dos indicadores é NaN: Na diz se não é número e Nz troca por um padrão.

var variacao = Nz(Closes.Change(5), 0);

Cruzamento para cima e para baixo

Crossed.Above(a, b)Crossed.Below(a, b)

Cruzamento neste candle, entre duas séries ou entre uma série e um nível.

private Sma curta = null!, longa = null!;public override void OnStart() { curta = new Sma(9); longa = new Sma(21); }public override void OnBarClose(){    curta.Update(Current); longa.Update(Current);    if (Crossed.Above(curta, longa) && Position.IsFlat) Buy(1);}

Indicadores

Como usar um indicador

Crie em OnStart e avance em OnBarClose com Update(Current) (o candle) ou Update(valor) (um número). Value é o de agora, Previous o do candle anterior, IsReady diz que saiu do aquecimento. A conta é a mesma do gráfico da HTS. Indicador com várias saídas expõe cada uma (Upper, Lower, Signal...) e o histórico com ...Ago(n). A lista completa, com um exemplo de cada, está na referência no fim deste manual.

private Bollinger bb = null!;public override void OnStart() { bb = new Bollinger(20, 2); }public override void OnBarClose(){    bb.Update(Current.Close);    if (!bb.IsReady) return;    if (Position.IsFlat && Current.Close < bb.Lower) Buy(1);    else if (Position.IsLong && Current.Close > bb.Value) ClosePosition();}

O gráfico

Desenhar uma série

Plot(nome, valor, estilo)

Desenha um valor da série nome neste candle: linha, histograma, pontos, área, degrau, cruz ou colunas. Plot(nome, valor, cor) pinta só este ponto (cor por valor).

Plot("Amplitude", Current.Range, PlotStyle.Histogram);Plot("Fechamento", Current.Close, Current.IsBullish ? "#22c55e" : "#ef4444");

Aparência padrão da série

StylePlot(nome, cor, espessura)

A aparência padrão da série; a pessoa ainda troca na "Aparência".

StylePlot("Fechamento", "#f59e0b", 2);

Preencher entre duas séries

FillBetween(a, b, cor)

Preenche entre duas séries, com cor própria (com transparência, ex.: rgba(...)).

Plot("Máxima", Current.High);Plot("Mínima", Current.Low);FillBetween("Máxima", "Mínima", "rgba(120,120,255,0.1)");

Linha horizontal

HLine(valor, cor, texto)

Uma linha horizontal fixa.

HLine(70, "#888888", "sobrecompra");

Pintar o candle e o fundo

PaintCandle(cor)BackgroundColor(cor)

Pinta o candle ou o fundo deste candle.

if (Current.Range > 300) PaintCandle("#f59e0b");if (Now.HHMM < 930) BackgroundColor("rgba(255,255,255,0.04)");

Marca no candle

Mark(texto, posicao, forma, cor)

Seta, ponto ou texto acima ou abaixo do candle.

if (Current.IsBullish) Mark("C", MarkerPosition.Below, MarkerShape.Arrow, "#22c55e");

Linha e caixa

DrawLineDrawBox

Linha ou caixa entre dois pontos (candles atrás, valor).

if (Candles.Count > 10) DrawLine(10, Candles[^11].Close, 0, Current.Close, "#ffffff");

Tabela no painel

Table(linha, coluna, texto)

Uma célula fixa no canto do painel.

Table(0, 0, $"Fechamento {Current.Close:0}");

Indicador sobre o preço

[Overlay]

Na classe do indicador, põe as séries sobre o preço; sem ele, o indicador ganha um painel próprio. Cores: "#rrggbb" (ou #rgb, #rrggbbaa, rgba(...)). Limites: 16 séries, 5.000 marcas, 500 desenhos, 50 níveis.

[Overlay]public class MediaNoPreco : Robot{    private Sma media = null!;    public override void OnStart() { media = new Sma(20); }    public override void OnBarClose() { media.Update(Current); if (media.IsReady) Plot("Média", media.Value); }}

Parâmetros

Parâmetro editável

[Parameter("Nome")]

Em um campo público, torna o valor editável na tela (automação, backtest e gráfico). Tipos: int, double, bool, string e qualquer enum seu (vira lista). No atributo: Min, Max, Step, Group, Description, Options (string vira lista) e Format (Time para int HHMM; Color, Symbol, Timeframe para string). Valor fora da faixa é erro na tela, nunca ajuste calado.

[Parameter("Contratos", Min = 1, Max = 10, Group = "Risco")] public int Contratos = 1;[Parameter("Zerar às", Format = ParameterFormat.Time)] public int ZerarAs = 1740;[Parameter("Lado", Options = new[] { "Compra", "Venda" })] public string Lado = "Compra";

Registros e alertas

Registro no diário

Log(mensagem)

Vai para o diário do backtest e da automação; com LogLevel muda a cor.

Log($"fechou em {Current.Close:0}");Log("perto do stop diário", LogLevel.Warning);

Alerta

Alert(mensagem)

Chama a atenção na hora: toast, bipe e o sino de Avisos no HTS, e uma seta no gráfico quando é indicador.

if (Current.Range > 500) Alert("candle de mais de 500 pontos");

Resultado e operações

Resultado da automação

Pnl

O resultado da automação: Day (realizado de hoje), Open (aberto), DayWithOpen (o que a meta e o stop diário olham), Total, DayDrawdown e DayRunup. O robô não lê o saldo da conta.

if (Pnl.DayWithOpen <= -500 && !Position.IsFlat) ClosePosition();

Operações fechadas

TradesTradesTodayLastTrade

As operações fechadas, com entrada, saída, contratos, resultado, Points, Mfe e Mae (maior excursão a favor e contra).

if (LastTrade is Trade t && t.Profit < 0) Log($"última perdeu {t.Points:0} pontos");var ganhosHoje = TradesToday.Count(x => x.Profit > 0);

Ganhos e perdas seguidos

ConsecutiveWinsConsecutiveLosses

Ganhos e perdas seguidos, hoje.

var contratos = ConsecutiveLosses >= 2 ? 1 : 2;if (Position.IsFlat && Current.IsBullish) Buy(contratos);

Bibliotecas

Código compartilhado

Um código sem robô dentro (só classes, structs, enums). Compile-a; a partir daí ela entra em todo robô e indicador seu na próxima compilação deles. Um problema dentro da biblioteca aparece na lista com o nome dela.

public static class Risco{    public static int Contratos(double perdaMaxima, double stopEmPontos, double valorDoPonto) =>        Math.Max(1, (int)(perdaMaxima / (stopEmPontos * valorDoPonto)));}

O que o código não pode usar

Arquivo, rede, reflexão, threads, processos, relógio (DateTime), aleatório, Console, unsafe, dynamic, extern. O compilador recusa com a linha e explica a troca (DateTime → Now, por exemplo). Cada chamada do robô ao vivo tem um limite de tempo (5 s): um laço infinito para o robô, não a plataforma.

Backtest

Escolha ativo, tempo gráfico e dias; patrimônio, slippage em ticks, corretagem por contrato, posição máxima, zerar no fim do dia e as mesmas regras da automação. O resultado traz métricas (líquido, acerto, payoff, fator de lucro, drawdown máximo), a curva, a lista de trades com MEP/MEN, as execuções, o diário e as recusas do motor. O backtest roda no HTS desktop (precisa do .NET do HTS, instalado uma vez).

Exemplos

O código de cada exemplo está na aba Exemplos do HT Code: abra, leia e use "Copiar código" para levar o código (ou partes dele) para o seu. Todos compilam e rodam como estão.

Primeiros passos

  • Cruzamento de médias com stop e alvo — O robô mais simples que vale a pena: compra quando a média curta cruza a longa para cima, vende quando cruza para baixo, sempre com stop e alvo em pontos. Só opera dentro do horário e zera no fim do dia pela regra da automação.
  • Uma biblioteca compartilhada e o robô que a usa (dois códigos) — A biblioteca é um código sem robô dentro (vai para "Bibliotecas" no explorador). Compilada, entra em todo robô e indicador seu na próxima compilação deles. Aqui os dois aparecem juntos só para facilitar a leitura; no HT Code a biblioteca é um código e o robô é outro.
  • Compra no candle de alta forte, com stop e alvo — O primeiro robô de verdade: quando o candle fecha de alta com corpo grande (força compradora), compra a mercado e já deixa stop e alvo em pontos. Ensina a ler o candle atual (Current), o anterior (CandleAgo) e a conferir se está zerado antes de entrar.
  • Janela de horário e número de contratos como parâmetros — Opera só entre o início e o fim escolhidos (horário de Brasília) e zera tudo no "zerar às", sem depender da regra da automação. A entrada é simples (rompe a máxima ou a mínima do candle anterior); o foco é mostrar parâmetros de horário (Format = Time), Now.Between, Now.HHMM e o limite de entradas por dia (EntriesToday).
  • Indicador mínimo que plota uma média no gráfico — Um indicador é um código que não manda ordem: só calcula e desenha. Com [Overlay], a linha fica sobre o preço (sem [Overlay], ganha um painel próprio embaixo). Ensina o ciclo básico: criar no OnStart, alimentar com Update no OnBarClose, esperar o aquecimento (IsReady) e plotar com cor e espessura.
  • Stop e alvo pelo preço executado, no OnFill, com Log — Em vez de stop e alvo em pontos logo depois do Buy, o robô espera a execução chegar (OnFill) e calcula stop e alvo a partir do PREÇO EXECUTADO (StopLossAt/TakeProfitAt). Ensina a dar nome à ordem, a distinguir a entrada da saída pelo nome e pela origem (Source) e a registrar tudo no Log.

Tendência e médias

  • Cruzamento de médias com filtro de ADX — Cruzamento de médias sozinho apanha muito no lateral. Aqui ele só vale quando o ADX mostra tendência (acima do mínimo) e o DI+ ou o DI- confirma o lado. Ensina a combinar dois indicadores: um que dá o sinal e outro que filtra quando o sinal merece confiança.
  • SuperTrend seguindo a tendência (sempre posicionado) — O SuperTrend troca de lado quando o preço fecha além da banda de ATR. O robô fica comprado na alta e vendido na baixa, virando a mão (Reverse) na troca. Ensina FlippedNow/IsUptrend, a virada de mão e a usar a própria linha do indicador como stop (StopLossAt), que anda junto a cada candle.
  • HiLo Activator com saída parcial — O HiLo compara o fechamento com a média das máximas e das mínimas: fechou acima, tendência de alta; abaixo, de baixa. O robô entra na virada com 2 contratos, realiza metade (ClosePartial) quando anda o alvo parcial e deixa o resto correr até o HiLo virar. Ensina saída em duas etapas e a medir os pontos a favor pelo preço médio.
  • SAR parabólico com stop no próprio SAR — Entra na virada do SAR a favor de uma média longa (só compra acima dela, só vende abaixo) e usa o ponto do SAR como stop móvel: a cada candle o stop sobe (ou desce) junto. Ensina a mover o stop por preço com StopLossAt e a filtrar o sinal de virada pelo lado da tendência maior.
  • Ichimoku, compra acima da nuvem — Compra quando a Tenkan cruza a Kijun para cima com o preço acima da nuvem (tendência de alta confirmada) e vende no espelho abaixo dela. Sai quando o preço volta para dentro da nuvem. Ensina as linhas do Ichimoku (a nuvem de hoje foi projetada 26 candles atrás), o preenchimento entre duas séries (FillBetween) e a saída por condição.
  • Pullback na EMA em tendência, com KAMA contra a lateralidade — Em tendência, o preço costuma voltar à média e seguir. O robô compra quando a mínima toca a EMA e o candle fecha de volta acima dela. A KAMA (média adaptativa, quase parada no lateral) serve de filtro: se ela andou pouco nos últimos candles, o mercado está de lado e o robô não entra. Ensina filtro de lateralidade pela inclinação de uma média.

Rompimentos e canais

  • Rompimento da máxima da abertura, com horário e calendário — Espera os primeiros minutos do pregão, marca a máxima e a mínima desse trecho e compra o rompimento. Mostra o uso de Now/Today, MinutesSinceOpen, B3Calendar (não opera na véspera de vencimento) e as séries dos candles.
  • Canal de Donchian 20 (a regra das tartarugas) — Compra quando o fechamento passa da máxima dos últimos 20 candles e vende quando perde a mínima. A saída é pelo canal curto do lado oposto (10 candles): sem alvo fixo, deixa a tendência correr. Ensina a comparar com o canal do candle ANTERIOR (UpperAgo/LowerAgo), senão o candle de agora nunca rompe a própria máxima.
  • Bollinger squeeze e rompimento — Volatilidade baixa costuma anteceder movimento forte. O robô guarda a largura das bandas numa série própria (Series) e marca "aperto" quando ela é a menor dos últimos N candles. Depois de um aperto, compra o fechamento acima da banda superior (ou vende abaixo da inferior). Ensina a criar uma série sua e a usar Lowest/BarsSince sobre ela.
  • Rompimento da máxima e da mínima do dia anterior — A máxima e a mínima de ontem são níveis que todo mundo olha. O robô compra o primeiro fechamento acima da máxima de ontem e vende o primeiro abaixo da mínima, no máximo uma vez por lado no dia. Ensina PreviousDay (o candle diário de ontem montado a partir do histórico), o controle "uma vez por dia" com Today e HLine para marcar os níveis.
  • Opening range com BuyStop e SellStop pendentes — Marca a máxima e a mínima dos primeiros minutos do pregão e, ao fim desse trecho, deixa uma compra stop acima e uma venda stop abaixo, uma única vez no dia. A que executar cancela a outra e ganha stop no lado oposto da faixa. Pendente que não executou até o meio-dia é cancelada. Ensina ordens pendentes com nome, OnFill e Cancel por horário.
  • Rompimento do canal de Keltner com stop pelo ATR — Compra o fechamento acima da banda superior do Keltner e vende abaixo da inferior. Stop e alvo não são fixos: valem um múltiplo do ATR do momento, arredondado ao tick de 5 pontos do WIN. Em dia agitado o stop abre, em dia calmo fecha. Ensina risco proporcional à volatilidade e a limitar o stop entre um mínimo e um máximo.

Reversão e osciladores

  • IFR com as regras da automação, resultado do dia e alerta — Compra IFR sobrevendido e vende sobrecomprado. Lê as regras da automação (não entra perto do "zerar às"), o resultado do dia (para de abrir depois de 2 perdas seguidas por conta própria) e avisa com Alert quando entra.
  • Bollinger, volta para a média — Quando o candle fecha fora da banda e o seguinte fecha de volta para dentro, o robô aposta na volta à média: o alvo não é fixo, é a linha do meio da banda, que anda a cada candle. Ensina a ler as bandas do candle anterior (LowerAgo, UpperAgo) e a sair por condição, deixando o stop em pontos só como proteção.
  • Estocástico cruzando em zona extrema — Compra quando a linha %K cruza a %D para cima com as duas abaixo de 20 e vende no espelho, acima de 80. Ensina a cruzar duas linhas do MESMO indicador (K e D, com o valor do candle anterior em [1] e DAgo(1)) e a exigir que o cruzamento aconteça dentro da zona: cruzar no meio do caminho não vale.
  • Williams %R a favor da tendência — Reversão curta dentro da tendência maior: com o preço acima da média de 50, compra quando o %R sai de baixo de −80 (correção acabando); abaixo da média, vende quando sai de cima de −20. Ensina a combinar um oscilador (que vai de −100 a 0) com um filtro de tendência e a proteger o lucro com BreakEven (stop vai para a entrada depois de andar a favor).
  • CCI voltando de −100 e de +100 — Compra quando o CCI volta para cima de −100 e vende quando volta para baixo de +100; a saída é o CCI cruzar o zero (a "volta" terminou), com stop em pontos por segurança. Ensina a sair pelo próprio indicador e a limitar o número de entradas por dia (EntriesToday), coisa que todo robô de reversão precisa em dia de tendência forte.
  • Divergência de IFR no fundo — O preço faz um fundo mais baixo que o anterior, mas o IFR faz um fundo mais alto: a venda está perdendo força. O robô acha os fundos com Swings (um fundo só é confirmado alguns candles depois, quando o preço já subiu dos dois lados) e lê o IFR no candle do fundo com ifr[atraso]. Ensina a guardar o "fundo anterior" e comparar dois pontos no tempo.

Fluxo: negócio, agressão e book

  • Ao vivo, por negócio e book (só no HTS desktop) — OnBook só chama ao vivo; OnTick chama ao vivo e, no backtest, em cada ponto da lupa de 1m (negócio sintético, sem agressor: aqui o robô não entra no backtest). Compra quando o book mostra mais compra do que venda nos 3 primeiros níveis e o último negócio foi agressão de compra; sai no stop/alvo do motor. A entrada da chamada seguinte espera a anterior chegar à posição: o motor garante.
  • Saldo de agressão do candle como gatilho (só ao vivo) — Aggression soma a agressão desde que o robô ligou; guardando o saldo no começo de cada candle, a diferença no fechamento é o saldo DAQUELE candle. Compra quando o candle fecha de alta com saldo de compra acima do mínimo e vende no espelho. No backtest a agressão é sempre zero: o robô roda, mas não entra (o candle não diz quem agrediu).
  • Desequilíbrio do book, com spread fechado (só ao vivo) — Lê o book em OnBook de dois jeitos: só o melhor nível (BestBid × BestAsk) e a soma dos 3 primeiros. Entra no OnTick quando os dois apontam o mesmo lado e o spread está fechado: spread aberto (mais que N ticks) é mercado sem liquidez, e aí não entra. No backtest não existe book: o robô roda sem entrar.
  • Lotes grandes em sequência (só ao vivo) — Conta negócios grandes (lote acima de N) agredindo o mesmo lado, um atrás do outro, dentro de poucos segundos: é o "player" entrando. Um lote grande do lado contrário zera a contagem. Ensina a guardar estado entre chamadas do OnTick e a usar o horário do negócio (TimeMs). No backtest a quantidade vem 0 e o agressor desconhecido: nunca conta.
  • VWAP do dia com confirmação da agressão — Compra quando o preço volta para cima da VWAP do dia e vende quando perde a VWAP; ao vivo, só entra se o saldo de agressão do candle confirmar o lado. Sem agressão (backtest), cai para a confirmação pelo próprio candle. Ensina a escrever um robô que funciona nos dois mundos: o fluxo melhora o sinal quando existe, e o sinal não depende dele.
  • Tape reading pela velocidade dos negócios (só ao vivo) — Conta em RecentTicks quantos negócios saíram no último minuto e para onde o preço foi nesse minuto. Mercado acelerando (muito mais negócios que o normal) e andando para um lado: entra a favor. Ensina a percorrer RecentTicks do mais novo para o mais antigo e a parar no corte de tempo. No backtest RecentTicks vem vazio: o robô roda sem entrar.
  • Absorção: muita agressão e o preço não anda (só ao vivo) — Se o vendedor agride forte num candle e mesmo assim o preço não cai (candle pequeno, fechando no terço de cima), tem alguém grande comprando no limite: a venda foi absorvida. O robô compra (e vende no espelho). Ensina a cruzar o fluxo com a forma do candle e a comparar com a amplitude média. No backtest não há agressão: o robô roda sem entrar.

Quant e estatística

  • Z-score do preço (reversão à média) — O z-score mede quantos desvios-padrão o fechamento está longe da média: z = (preço − média) / desvio. Abaixo de −2 o preço está "esticado" para baixo; o robô compra quando o z volta a subir e sai quando chega a zero (a média). Ensina Closes.Average e Closes.StdDev e a guardar o próprio indicador numa Series para comparar com o candle anterior.
  • Regime de volatilidade (só opera no meio da distribuição) — Guarda o ATR de cada candle numa Series e calcula, sobre os últimos 200, os percentis 30 e 80. Mercado parado demais (abaixo do 30) não paga o stop; nervoso demais (acima do 80) violina. Fora dessa faixa o cruzamento de médias é ignorado. Ensina Percentile como filtro de regime, que serve para qualquer estratégia.
  • Momentum de séries temporais — Fica do lado do retorno dos últimos N candles: retorno positivo, comprado; negativo, vendido. Para não virar a mão a cada ruído, o retorno é dividido pela volatilidade (HistoricalVolatility) e só conta quando passa de um limiar. Ensina PercentChange, HistoricalVolatility e Reverse (vira a posição numa ordem só).
  • Regressão linear com R² como filtro — Ajusta uma reta aos últimos N fechamentos. A inclinação (Slope) diz a direção, em pontos por candle; o R² (0 a 1) diz quanto a reta explica o preço: perto de 1 é tendência limpa, perto de 0 é bagunça. Só opera com R² alto, comprando o recuo até a reta na alta e vendendo o repique na baixa. Ensina LinearRegression, Slope, R2 e Forecast.
  • Correlação WIN × WDO — Índice e dólar costumam andar em sentidos opostos. O robô lê o WDO de 5m com [UsesSeries], calcula a correlação dos retornos dos dois e, com correlação bem negativa, só compra WIN se o dólar caiu no candle (e vende se subiu). No backtest a tela manda o WDO pronto (as barras do gráfico); sem candles do dólar (sem histórico no período, ou no começo do pregão), o robô avisa uma vez e opera sem o filtro. Ensina Correlation e Series.
  • Rompimento por percentil 95 da amplitude — Um candle "fora da curva" é o que tem amplitude maior que 95% dos últimos 200. Quando ele aparece fechando perto da ponta (máxima na alta, mínima na baixa), o robô entra a favor. Ensina a calcular o percentil ANTES de incluir o candle atual (senão ele se compara consigo mesmo) e a usar a própria amplitude como medida do stop.
  • Quantidade de contratos pela volatilidade — O risco em reais por operação é fixo; o que muda é o tamanho. Contratos = risco ÷ (stop em pontos × valor do ponto), com o stop em múltiplos do ATR: mercado calmo, stop curto e mais contratos; nervoso, stop longo e menos contratos. Ensina SymbolInfo.PointValue (WIN: R$ 0,20 por ponto), arredondamento e Shifted (máxima dos candles ANTERIORES).

Rastreadores de preço e alertas

  • Aviso de nova máxima e nova mínima do dia — Indicador que vigia o pregão: desenha a máxima e a mínima do dia em degrau e, quando um candle fecha renovando uma delas, marca o candle e avisa com Alert. Só avisa a máxima que ficou de pé por alguns candles (em tendência, não avisa a cada candle). Ensina a guardar estado por dia (zerando na virada), CurrentDay e contadores entre candles.
  • Preço tocando os pivôs do dia anterior — Calcula os pivôs clássicos com a máxima, a mínima e o fechamento de ontem (PreviousDay + Pivots.Classic) e marca o candle que encosta em um deles, com uma tolerância em pontos. Cada nível só avisa uma vez por dia. Ensina a ler o dia anterior agregado e a evitar avisos repetidos guardando o que já tocou.
  • Gap de abertura contra o fechamento de ontem — No primeiro candle do dia compara a abertura com o fechamento do dia anterior. Gap maior que o mínimo vira marca, alerta e uma caixa (DrawBox) do tamanho do gap; depois acompanha se o gap foi fechado no mesmo dia. Ensina IsFirstCandleOfDay, PreviousDay e desenho entre dois pontos.
  • Candle de volume anormal — Painel próprio com o volume em colunas e a linha de corte (média + N desvios-padrão dos últimos candles). O candle cujo volume passa do corte é pintado no gráfico de preço e ganha uma marca. Ensina a ler a série Volumes por posição (Volumes[1] = candle anterior), cor por valor e o cuidado de comparar com a janela ANTERIOR ao candle.
  • Distância do VWAP em desvios — Painel próprio que mostra quantos desvios-padrão o fechamento está longe do VWAP do dia (um "z-score" do VWAP). Pinta o fundo quando passa de ±2 e avisa quando o preço volta de lá. Ensina Vwap (zera sozinho a cada pregão), StdDev alimentado com a diferença preço − VWAP e HLine para as faixas de referência.
  • Padrões de candle marcados no gráfico — Procura martelo, estrela cadente, engolfo de alta e engolfo de baixa (Patterns, com a mesma régua do catálogo do gráfico) e marca cada um com texto e cor. Um filtro opcional só mostra o padrão a favor da média longa. Ensina a chamar Patterns com o índice do candle atual e a montar a lista de achados para uma marca só.
  • Painel com o resumo do dia — Uma tabela (Table) no canto do gráfico com abertura, máxima, mínima, amplitude, variação contra o fechamento de ontem, volume e a posição do preço dentro da faixa do dia. Ensina CurrentDay e PreviousDay (agregados prontos), a grade de linhas e colunas da Table e a formatação dos números.

Gestão de risco e ordens

  • Rompimento com ordens pendentes, alvo limitado e stop móvel — Ordens completas: em vez de comprar a mercado no fechamento, o robô deixa uma COMPRA STOP acima do canal e uma VENDA STOP abaixo dele. O nome é único: colocar de novo "rompe-cima" no candle seguinte SUBSTITUI a anterior (o canal anda). Quando uma executa (OnFill), cancela a outra, põe o alvo como ordem LIMITADA (só reduz a posição) e liga o stop móvel e o break-even. Pendente vale no dia: o motor cancela na virada (e avisa em OnOrderCanceled).
  • Saída parcial no primeiro alvo e stop no preço de entrada — Entra com vários contratos no cruzamento de médias. Quando a posição anda o primeiro alvo a favor, realiza metade com ClosePartial e leva o stop do resto para o preço médio (StopLossAt): daí em diante a operação não perde. O resto sai no alvo final ou no stop. Ensina Position.OpenPoints, Position.Contracts e a ordem das chamadas numa decisão.
  • Stop móvel pela volatilidade (ATR) — Em vez de um stop fixo em pontos, o stop fica a N vezes o ATR do preço e só anda a favor: a cada candle o robô calcula o stop novo e, se for melhor que o atual, move com StopLossAt. Mercado calmo, stop curto; mercado nervoso, stop largo. O stop aparece no gráfico como pontos. Ensina Atr, StopLossAt e o arredondamento ao tick do ativo.
  • Stop diário e meta do próprio robô — Além das regras da automação, o robô vigia o resultado do dia em reais (Pnl.DayWithOpen: o realizado mais o aberto). Bateu a perda máxima ou a meta, zera, cancela as pendentes e encerra o dia por conta própria: só volta a operar no pregão seguinte. Ensina Pnl, TradesToday, guardar o dia encerrado e mostrar o placar numa Table.
  • Quantidade de contratos pelo risco em reais — O tamanho da mão sai da conta: perda máxima por operação ÷ (stop em pontos × valor do ponto do ativo). Stop curto permite mais contratos, stop longo menos, e a perda em reais fica a mesma. O stop é a mínima do candle de sinal (ou a máxima, na venda). Ensina SymbolInfo.PointValue, o arredondamento para baixo e o limite de contratos.
  • Compra limitada que acompanha o preço (Modify) e trata recusa e cancelamento — Em tendência de alta (preço acima da média), deixa uma COMPRA LIMITADA um pouco abaixo da mínima do último candle e, a cada candle, sobe a ordem com Modify em vez de cancelar e mandar outra. A tendência virou: cancela. Executou: stop e alvo. OnOrderCanceled e OnOrderRejected contam o que aconteceu; três recusas no dia param a pendente.

Indicadores no gráfico

  • Indicador no gráfico com bandas, preenchimento e cor por valor — Sem automação (não manda ordem): vira estudo em "Meus indicadores". Mostra StylePlot, FillBetween, cor por valor, PaintCandle, BackgroundColor e a tabela (Table) no canto do painel.
  • Heikin-Ashi pintando os candles do gráfico — Calcula os candles Heikin-Ashi (médias que suavizam o ruído) e pinta cada candle normal com a cor do Heikin-Ashi: verde em sequência de alta, vermelho em sequência de baixa, e uma cor mais fraca quando o Heikin-Ashi tem sombra contra a tendência (perda de força). Marca a virada de cor. Ensina HeikinAshi, CandleAgo e PaintCandle.
  • Renko sobre o gráfico, com marcas de virada — Monta tijolos Renko de tamanho fixo em pontos sobre o fechamento dos candles e desenha o nível do último tijolo em degrau, com a cor do lado. Quando o Renko vira de lado, marca o candle e conta a sequência de tijolos. Ensina Renko (Bricks, NewBricks, FlippedNow, Direction) e a diferença entre o tempo do candle e o "tempo" do tijolo.
  • MACD em painel próprio com histograma de quatro cores — Sem [Overlay], o indicador ganha um painel com escala própria. Plota a linha do MACD, a linha de sinal e o histograma colorido pelo sinal E pela força: verde forte subindo, verde fraco caindo, vermelho forte descendo, vermelho fraco voltando. Ensina Macd (Line, Signal, Histogram, HistogramAgo) e o estilo definido pelo primeiro Plot.
  • Pivôs do dia (clássico, Fibonacci ou Camarilla) com zona e tabela — Calcula os pivôs com o dia anterior e desenha os sete níveis em degrau (cada dia com os seus), preenche a zona entre S1 e R1 e mostra os valores de hoje numa Table. Ensina a escolher o cálculo por parâmetro (enum), Pivots, FillBetween entre duas séries e por que níveis que mudam por dia vão em Plot (degrau), e não em HLine.
  • Canal de regressão linear com preenchimento — Ajusta uma reta aos últimos N fechamentos (mínimos quadrados) e desenha a linha central e as bandas a N erros-padrão, com a área entre elas preenchida. A cor da linha central segue a inclinação, e o candle que fecha fora do canal é pintado. Ensina RegressionChannel (Upper, Lower, Slope), LinearRegression.R2 e FillBetween.

Referência da API

Tudo o que o robô pode usar está aqui; o resto o compilador recusa.

API · Robô e contexto

O robô

Robot

A classe-base de todo robô da HTS. Seu robô herda dela, declara os parâmetros com ParameterAttribute e escreve a decisão em OnBarClose (no fechamento de cada candle) e, se quiser entrar no meio do candle assim que a condição bater, em OnTick (a cada negócio). Regras que o motor garante e que o robô não precisa (nem consegue) burlar: uma chamada por evento: candle fechado (OnBarClose) e, se o robô implementar, negócio (OnTick) e book (OnBook). No backtest o OnTick também roda: o motor anda DENTRO de cada candle pelos candles de 1m (abertura, máxima e mínima na ordem provável, fechamento; sem 1m, os 4 pontos do próprio candle) e chama o robô em cada ponto; numa chamada, quantas ordens a mercado o robô quiser (Buy, Sell, ClosePosition, ClosePartial, Reverse), até 20 (a 21ª é recusada: ORDENS_DEMAIS). Elas saem em sequência e cada uma é conferida pela posição que as anteriores deixam: Buy(1); ClosePosition(); compra e zera; entre chamadas, a entrada nova espera a anterior chegar à posição (ao vivo): o robô que compra "enquanto zerado" a cada negócio não dobra a mão. A recusa vem com ORDEM_EM_ANDAMENTO; pendentes (limite, stop, stop-limite): até 20, com nome único, valem no dia; as regras da automação (horário, stop diário, meta, perdas seguidas, operações, posição máxima) são do motor.

public class CompraNoRompimento : Robot{    [Parameter("Stop (pontos)", Min = 50, Max = 1000)] public int Stop = 150;    public override void OnBarClose()    {        // compra quando o candle fecha acima da máxima do anterior        if (Position.IsFlat && Current.Close > Highs[1]) { Buy(1); StopLoss(Stop); }    }}
MembroO que faz
IContext ContextO contexto da chamada atual. Só existe entre OnStart e OnStop.
virtual void OnStart()Uma vez, antes do primeiro candle. Crie aqui os indicadores.
abstract void OnBarClose()A cada candle fechado. É aqui que o robô decide.
virtual void OnTick(Tick tick)A cada negócio do mercado: para entrar (ou sair) no meio do candle, assim que a condição bater. Manda ordem como o OnBarClose (várias a mercado por chamada, até 20). Ao vivo, é cada negócio da bolsa. No backtest, o motor anda dentro de cada candle pelos candles de 1m e chama aqui em cada ponto: abertura → mínima e máxima na ordem provável (1m de alta: a mínima antes; de baixa: a máxima antes) → fechamento; sem 1m, os 4 pontos do próprio candle. O negócio do backtest é sintético: o preço do ponto, quantidade 0 e agressor desconhecido (Flat); a ordem a mercado executa no preço do ponto com o slippage; stop, alvo e pendentes são conferidos ponto a ponto (a pendente posta num ponto vale a partir do seguinte). Candles e Current continuam no último candle FECHADO (o que está se formando não aparece), como ao vivo. Quem não precisa, não implementa: sem ele, o backtest é só por candle fechado.
virtual void OnBook(Book book)A cada mudança do book, SÓ AO VIVO (não há book histórico no backtest). As mesmas regras de OnTick.
virtual void OnStop()Uma vez, depois do último candle (ou quando o robô é desligado).
IReadOnlyList<Candle> CandlesCandles fechados até agora, do mais antigo ao atual. O último é Current.
Candle CurrentO candle que acabou de fechar e motivou a chamada de OnBarClose. Em OnTick, o último candle FECHADO (o que está se formando não aparece, ao vivo e no backtest).
Position PositionPosição líquida agora, depois das execuções do candle anterior.
SymbolInfo SymbolInfoO ativo e o contrato (tick, valor do ponto).
double DayProfitResultado realizado do dia (em dinheiro), já com corretagem no backtest. Ao vivo, o realizado do dia do robô na conta (Simulador ou MT5).
double EquityPatrimônio agora: inicial + realizado + aberto ao fechamento do candle atual.
bool StoppedForDayO robô encerrou o dia (stop diário, meta, perdas seguidas ou "zerar às"). Enquanto true, entradas são recusadas e o motor zera o que aparecer, até o próximo pregão. Saídas passam sempre.
Book BookO book de agora (ao vivo; vazio no backtest).
Tick? LastTickO último negócio (ao vivo; no backtest, o ponto sintético do OnTick, ou null sem ele).
void Buy(int quantity = 1)Compra a mercado. No backtest executa no fechamento deste candle (em OnBarClose) ou no preço do ponto (em OnTick), mais o slippage configurado. Pode haver outras na mesma chamada (até 20, em sequência).
void Sell(int quantity = 1)Vende a mercado. Como Buy, menos o slippage.
void ClosePosition()Zera a posição a mercado: a de agora mais as ordens a mercado já pedidas nesta chamada (Buy(1); ClosePosition(); zera a compra). Sem posição, não faz nada.
void StopLoss(double points)Stop de perda a points do preço médio da posição (a que existe ou a que esta decisão abrir). Executa como ordem a mercado no candle em que o preço tocar (com OnTick no backtest, no ponto em que tocar, a partir do seguinte), com slippage. Chamar de novo substitui o anterior; CancelStops remove.
void TakeProfit(double points)Alvo (realização) a points do preço médio, a favor. Executa no toque, sem slippage.
void CancelStops()Remove stop e alvo pendentes.
void Log(string message)Registro que aparece no painel do backtest e no diário do robô ao vivo.
void Log(string message, LogLevel level)Registro com nível: Log("x", LogLevel.Warning).
void Alert(string message)Alerta: aviso na hora no HTS (toast, som, sino) e seta no gráfico.
void Plot(string name, double value, PlotStyle style = PlotStyle.Line)Plota um valor da série name neste candle: é o que o gráfico desenha (indicador) e o que o painel do backtest mostra. Uma série, um valor por candle; chamar de novo no mesmo candle substitui. Candle sem chamada fica sem valor (buraco na linha). O estilo vale da primeira chamada da série. Valor não finito = sem valor.
void Plot(string name, double value, string color)Plota com a cor deste ponto (cor por valor).
void StylePlot(string name, string? color, double width = 0)Cor e espessura padrão da série.
void FillBetween(string seriesA, string seriesB, string? color = null)Preenche entre duas séries.
void HLine(double value, string? color = null, string? text = null)Linha horizontal no painel.
void PaintCandle(string color)Pinta o candle atual.
void BackgroundColor(string color)Pinta o fundo da coluna do candle atual.
void Mark(string text, MarkerPosition position = MarkerPosition.Above, MarkerShape shape = MarkerShape.Arrow, string? color = null)Marca no candle atual (seta, ponto ou texto; acima da máxima ou abaixo da mínima).
void Mark(string text, double value, MarkerPosition position = MarkerPosition.Above, MarkerShape shape = MarkerShape.Arrow, string? color = null)Marca ancorada num valor.
void DrawLine(int barsAgo1, double value1, int barsAgo2, double value2, string? color = null)Linha entre dois pontos (candles atrás, valor).
void DrawBox(int barsAgo1, double value1, int barsAgo2, double value2, string? color = null)Caixa entre dois cantos (candles atrás, valor).
void Table(int row, int column, string text)Célula da tabela no canto do painel.
Timestamp NowO momento deste evento em Brasília: no fechamento de candle, o fim do candle (End quando a barra traz); num negócio/book, a hora dele. Ao vivo, nunca volta (o candle que chega depois de um negócio mais novo fica com a hora do negócio). if (Now.HHMM >= 1750) ClosePosition();
Date TodayO pregão deste evento (a data do candle que fechou, ou do negócio).
int SecondsPerCandleO tempo gráfico em segundos (300 = 5 min); 0 nos gráficos atemporais (Renko, Range, Pontos, Ponto e figura, negócios, volume), em que a barra não tem duração fixa, e quando não se sabe. if (SecondsPerCandle == 0) Log("gráfico atemporal: a barra não tem duração fixa (Current.End é o fim do minuto em que fechou)");
bool IsFirstCandleOfDayO candle atual é o primeiro do dia no histórico.
Bar? CurrentDayO dia até agora: abertura do primeiro candle do dia, máxima, mínima, fechamento atual, volume.
Bar? PreviousDayO dia anterior inteiro (o que está no histórico); null se não está.
Bar? CurrentWeekA semana até agora (de segunda-feira).
Bar? CurrentMonthO mês até agora.
AutomationRules RulesAs regras escolhidas na tela (horário, leilão, meta, stop diário, perdas seguidas, operações, posição máxima). O motor vigia: o robô só lê, por exemplo para não tentar entrar fora da janela. if (Rules.FlattenAt is int z && Now.HHMM >= z - 5) return; // perto de zerar, não entra
SessionState SessionO estado do pregão (ao vivo): aberto, leilão, fechado; no backtest, desconhecido.
int? MinutesSinceOpenMinutos desde o primeiro candle do dia (no atemporal, o minuto em que fechou a primeira barra de hoje); null sem candle hoje.
int EntriesTodayEntradas que a automação fez hoje.
int ConsecutiveLossesFechamentos seguidos com perda, hoje.
string? StopReasonPor que a automação encerrou o dia; null se não encerrou.
Pnl PnlO resultado da automação: Pnl.Day (realizado de hoje), Open, DayWithOpen, Total, DayDrawdown e DayRunup. if (Pnl.DayWithOpen >= 500) ClosePosition();
IReadOnlyList<Trade> TradesAs operações fechadas pela automação (no backtest, todas; ao vivo, desde que o robô foi ligado).
IReadOnlyList<Trade> TradesTodayAs operações fechadas hoje.
Trade? LastTradeA última operação fechada; null se ainda não houve.
int ConsecutiveWinsFechamentos seguidos com ganho, hoje.
Candle? CandleAgo(int barsAgo)O candle barsAgo posições antes do atual (0 = o atual). Fora do histórico devolve null.
CandleSeries ClosesOs fechamentos como série: Closes[1] é o do candle anterior (como close[1]). Closes.Average(20), Closes.Rising(3)...
CandleSeries OpensAs aberturas como série.
CandleSeries HighsAs máximas como série (Highs.Highest(20) = a maior máxima de 20 candles e há quantos foi).
CandleSeries LowsAs mínimas como série.
CandleSeries VolumesOs volumes como série.
static bool Na(double v)O valor não é um número (NaN do aquecimento de um indicador, por exemplo). O na do Pine.
static double Nz(double v, double fallback = 0)O valor, ou fallback quando não é um número. O nz do Pine.
virtual void OnFill(Fill fill)Uma ordem do robô executou (inteira ou em parte): a mercado, pendente, stop/alvo do motor, regra, fim do dia. No backtest chega antes do OnBarClose do candle em que executou (ou logo depois dele, para a ordem do próprio candle); ao vivo, quando a corretora confirma. Aqui dá para pôr stop, alvo, pendentes e ordem a mercado (no backtest, a ordem a mercado pedida aqui executa no mesmo preço da execução que avisou). Só depois da zeragem do fim do dia não sai ordem a mercado (MERCADO_DEPOIS_DA_DECISAO).
virtual void OnOrderRejected(PendingOrder order, string code, string message)Uma ordem foi recusada: pelas regras da automação (horário, posição máxima...), pelo teto, pela conta ou pela corretora.
virtual void OnOrderCanceled(PendingOrder order, string reason)Uma pendente foi cancelada: pelo robô, por outra de mesmo nome, pelo motor (fim do dia, teto, encerramento, janela, saída pelo stop) ou de fora.
void Buy(int quantity, string name, string? comment = null)Compra a mercado com nome e comentário.
void Sell(int quantity, string name, string? comment = null)Vende a mercado com nome e comentário.
void BuyLimit(int quantity, double price, string? name = null, string? comment = null)Compra limitada (pendente). BuyLimit(1, Current.Low - 50, "pullback");
void SellLimit(int quantity, double price, string? name = null, string? comment = null)Venda limitada (pendente).
void BuyStop(int quantity, double stopPrice, string? name = null, string? comment = null)Compra stop (pendente). BuyStop(1, Highs.Highest(20).Value + 5, "rompimento");
void SellStop(int quantity, double stopPrice, string? name = null, string? comment = null)Venda stop (pendente).
void BuyStopLimit(int quantity, double stopPrice, double limitPrice, string? name = null, string? comment = null)Compra stop-limite (pendente; só no Simulador).
void SellStopLimit(int quantity, double stopPrice, double limitPrice, string? name = null, string? comment = null)Venda stop-limite (pendente; só no Simulador).
bool Cancel(string name)Cancela a pendente pelo nome.
void CancelAll()Cancela todas as pendentes.
bool Modify(string name, double price)Muda o preço (limite) ou o gatilho (stop) da pendente.
void ClosePartial(int quantity)Zera parte da posição a mercado.
void Reverse()Vira a mão a mercado.
void TrailingStop(double points)Stop móvel a N pontos.
void BreakEven(double triggerPoints, double offsetPoints = 0)Break-even: no gatilho (pontos a favor), o stop vai ao preço médio mais a folga.
void StopLossAt(double price)Stop num preço.
void TakeProfitAt(double price)Alvo num preço.
IReadOnlyList<PendingOrder> PendingOrdersAs pendentes de agora.
IReadOnlyList<Candle> CandlesOf(string timeframe)Os candles fechados de outro tempo do mesmo ativo (declare [UsesSeries("15m")]). var h = CandlesOf("60m");
IReadOnlyList<Candle> CandlesOf(string symbol, string timeframe)Os candles fechados de outro ativo (declare [UsesSeries("WDOFUT", "5m")]; no backtest, a série pronta da tela).
IReadOnlyList<Tick> RecentTicksOs últimos negócios (até 500; só ao vivo).
Aggression AggressionA agressão desde que ligou (só ao vivo).
double? SettlementO ajuste do dia (só ao vivo; null sem o dado).

O contexto do robô

IContext (interface)

Tudo que o robô sabe e tudo que ele pode fazer chega por aqui. O robô nunca lê relógio, rede ou arquivo: o tempo e o preço são os do evento (o candle que fechou, ou o negócio) e a ordem vai para o motor, que decide o que executar. No backtest e ao vivo os comandos são os mesmos. ORDENS A MERCADO. Uma chamada do robô (OnBarClose, OnTick, OnBook, ou um evento de ordem que chega como chamada nova) pode mandar várias, até 20 (a 21ª é recusada: ORDENS_DEMAIS). Saem em sequência, e cada uma é conferida pela posição que as anteriores deixam (Buy(1); ClosePosition(); compra e zera; ClosePosition, ClosePartial e Reverse contam as ordens já pedidas na chamada). Ao vivo, entre uma chamada e a seguinte a entrada nova espera a anterior chegar à posição (ORDEM_EM_ANDAMENTO): nunca dobra a mão no escuro. Os eventos de ordem (OnFill, OnOrderRejected, OnOrderCanceled) também mandam a mercado; no backtest, no mesmo preço da decisão. Só depois da zeragem do fim do dia não sai ordem a mercado (MERCADO_DEPOIS_DA_DECISAO).

// Context é o que os atalhos do robô (Candles, Position, Buy...) usam por baixoLog($"candle {Context.Index + 1} de {Context.Candles.Count}, posição {Context.Position.Quantity}");if (Context.Position.IsFlat && Context.Current.IsBullish) Context.Buy(1);
MembroO que faz
SymbolInfo SymbolInfoO ativo e o contrato (tick, valor do ponto).
IReadOnlyList<Candle> CandlesCandles fechados até agora, do mais antigo ao atual. O último é Current.
Candle CurrentO candle que acabou de fechar e motivou a chamada de OnBarClose. Em OnTick, o último candle FECHADO (o que está se formando não aparece, ao vivo e no backtest).
int IndexÍndice de Current em Candles.
Timestamp NowO momento DESTE evento, em Brasília (nunca o relógio do PC): no fechamento de candle, o FIM do candle (o de 5 min das 17:45 fecha às 17:50; com End, é ele); num negócio ou num book, a hora dele. Ao vivo, nunca volta: o candle que chega depois de um negócio mais novo (a última barra do pregão de um tempo como 45m, que só fecha no pregão seguinte; os tijolos que fecharam no mesmo minuto) fica com a hora desse negócio.
Date TodayO pregão deste evento: a data do candle que fechou, ou a data do negócio/book. Ao vivo, o candle de um pregão que já passou (que chegou hoje) não volta o pregão: continua o de hoje.
int SecondsPerCandleA duração do candle em segundos (o tempo gráfico: 300 = 5 min, 7200 = 2 h). 0 nos gráficos atemporais (Renko, Range, Pontos, Ponto e figura, negócios, volume): a barra não tem duração fixa, e o End dela é o fim do minuto em que fechou (precisão de minuto; não quanto ela levou para se formar). Também 0 quando não deu para saber.
Book BookO book de agora (ao vivo); no backtest, Empty.
Tick? LastTickO último negócio visto (ao vivo). No backtest, o ponto sintético do OnTick (preço do ponto, quantidade 0, agressor Flat), ou null para o robô sem ele.
Position PositionPosição líquida agora, depois das execuções do candle anterior.
double DayProfitResultado realizado do dia (em dinheiro), já com corretagem no backtest. Ao vivo, o realizado do dia do robô na conta (Simulador ou MT5).
double EquityPatrimônio agora: inicial + realizado + aberto ao fechamento do candle atual.
bool StoppedForDayO robô encerrou o dia (stop diário, meta, perdas seguidas ou "zerar às"). Enquanto true, entradas são recusadas e o motor zera o que aparecer, até o próximo pregão. Saídas passam sempre.
string? StopReasonPor que encerrou o dia (em palavras); null se não encerrou.
AutomationRules RulesAs regras da automação: o motor vigia, o robô só lê.
SessionState SessionO estado do pregão do ativo (ao vivo, informado pela bolsa); no backtest, Unknown.
int? MinutesSinceOpenMinutos desde o início do primeiro candle do dia até Now; null sem candle hoje. Nos gráficos atemporais o primeiro candle do dia é o minuto em que fechou a primeira barra de hoje (não a abertura do pregão).
int EntriesTodayEntradas (a partir de zerada) que a automação fez hoje.
int ConsecutiveLossesFechamentos seguidos com perda, hoje (um fechamento com ganho volta a zero).
int ConsecutiveWinsFechamentos seguidos com ganho, hoje (um fechamento com perda volta a zero).
Pnl PnlO resultado da automação: dia, aberto, acumulado, drawdown e runup do dia.
IReadOnlyList<Trade> TradesAs operações fechadas pela automação: todas no backtest; ao vivo, desde que o robô foi ligado.
IReadOnlyList<Trade> TradesTodayAs operações fechadas hoje.
void Buy(int quantity)Compra a mercado. No backtest executa no fechamento deste candle (em OnBarClose) ou no preço do ponto (em OnTick), mais o slippage configurado. Pode haver outras na mesma chamada (até 20, em sequência).
void Sell(int quantity)Vende a mercado. Como Buy, menos o slippage.
void ClosePosition()Zera a posição a mercado: a de agora mais as ordens a mercado já pedidas nesta chamada (Buy(1); ClosePosition(); zera a compra). Sem posição, não faz nada.
void StopLoss(double points)Stop de perda a points do preço médio da posição (a que existe ou a que esta decisão abrir). Executa como ordem a mercado no candle em que o preço tocar (com OnTick no backtest, no ponto em que tocar, a partir do seguinte), com slippage. Chamar de novo substitui o anterior; CancelStops remove.
void TakeProfit(double points)Alvo (realização) a points do preço médio, a favor. Executa no toque, sem slippage.
void CancelStops()Remove stop e alvo pendentes.
void Log(string message)Registro que aparece no painel do backtest e no diário do robô ao vivo.
void Log(string message, LogLevel level)Registro com nível: info, aviso ou erro colorem o diário; alerta é Alert.
void Alert(string message)Alerta: no HTS vira aviso na hora (toast, som e o sino de Avisos) e, no indicador no gráfico, uma seta com o texto acima do candle.
void Plot(string name, double value, PlotStyle style = PlotStyle.Line)Plota um valor da série name neste candle: é o que o gráfico desenha (indicador) e o que o painel do backtest mostra. Uma série, um valor por candle; chamar de novo no mesmo candle substitui. Candle sem chamada fica sem valor (buraco na linha). O estilo vale da primeira chamada da série. Valor não finito = sem valor.
void Plot(string name, double value, string color)Plota o valor com a cor DESTE ponto (cor por valor): Plot("sinal", v, v > 0 ? "#22c55e" : "#ef4444").
void StylePlot(string name, string? color, double width = 0)A aparência padrão da série (cor e espessura); o gráfico ainda deixa trocar na "Aparência".
void FillBetween(string seriesA, string seriesB, string? color = null)Preenche a área entre duas séries plotadas (bandas, nuvem). color é a cor do preenchimento (com alfa, ex.: "rgba(120,120,255,0.1)"; sem alfa, a tela aplica transparência); a "Aparência" deixa trocar.
void HLine(double value, string? color = null, string? text = null)Uma linha horizontal no painel (70 e 30 do IFR, zero do MACD...), com texto opcional.
void PaintCandle(string color)Pinta o corpo do candle atual.
void BackgroundColor(string color)Pinta o fundo da coluna do candle atual.
void Mark(string text, MarkerPosition position = MarkerPosition.Above, MarkerShape shape = MarkerShape.Arrow, string? color = null)Uma marca no candle atual: seta, ponto ou só texto, acima da máxima ou abaixo da mínima.
void Mark(string text, double value, MarkerPosition position = MarkerPosition.Above, MarkerShape shape = MarkerShape.Arrow, string? color = null)Uma marca ancorada num valor (preço ou valor do painel).
void DrawLine(int barsAgo1, double value1, int barsAgo2, double value2, string? color = null)Uma linha de (candle barsAgo1 atrás, valor1) a (candle barsAgo2 atrás, valor2). 0 = o candle atual.
void DrawBox(int barsAgo1, double value1, int barsAgo2, double value2, string? color = null)Uma caixa com os mesmos cantos.
void Table(int row, int column, string text)Uma célula da tabela no canto do painel (até 10×10): números do robô que a pessoa quer ver.
void Buy(int quantity, string name, string? comment = null)Compra a mercado com nome (para os eventos) e comentário.
void Sell(int quantity, string name, string? comment = null)Vende a mercado com nome e comentário.
void BuyLimit(int quantity, double price, string? name = null, string? comment = null)Compra limitada a price (ou menos). No backtest executa no candle SEGUINTE em que a mínima tocar, sem slippage (abertura abaixo = executa na abertura).
void SellLimit(int quantity, double price, string? name = null, string? comment = null)Venda limitada a price (ou mais).
void BuyStop(int quantity, double stopPrice, string? name = null, string? comment = null)Compra stop: quando o preço chegar a stopPrice, compra a mercado (no backtest, com slippage; abertura acima = na abertura).
void SellStop(int quantity, double stopPrice, string? name = null, string? comment = null)Venda stop: quando o preço cair a stopPrice, vende a mercado.
void BuyStopLimit(int quantity, double stopPrice, double limitPrice, string? name = null, string? comment = null)Compra stop-limite: no stopPrice vira compra limitada a limitPrice (≥ gatilho). Só no Simulador (na conta MT5 o motor recusa com STOP_LIMITE_SO_SIMULADOR). No backtest, se o candle abrir acima do limite, a ordem vira limitada e só volta a ser conferida no candle seguinte.
void SellStopLimit(int quantity, double stopPrice, double limitPrice, string? name = null, string? comment = null)Venda stop-limite: no stopPrice vira venda limitada a limitPrice (≤ gatilho).
bool Cancel(string name)Cancela a pendente name. false = não há pendente com esse nome.
void CancelAll()Cancela todas as pendentes do robô.
bool Modify(string name, double price)Muda o preço da pendente name: na limitada, o limite; no stop, o gatilho; no stop-limite, o gatilho, e o limite anda junto (mantém a distância). false = não há pendente com esse nome.
void ClosePartial(int quantity)Zera PARTE da posição a mercado (só reduz: nunca vira a mão). Sem posição, não faz nada.
void Reverse()Vira a mão a mercado (comprado 2 → vendido 2). Cancela stop, alvo, stop móvel e break-even da posição velha e as pendentes de saída dela; o robô pede a proteção da posição nova na mesma chamada. Sem posição, não faz nada.
void TrailingStop(double points)Stop móvel a points: começa como StopLoss e anda a favor (comprado: a máxima menos os pontos), nunca contra. No backtest anda pela máxima/mínima de cada candle e vale a partir do candle seguinte; ao vivo, a cada negócio. CancelStops remove.
void BreakEven(double triggerPoints, double offsetPoints = 0)Break-even: quando o preço andar triggerPoints a favor do preço médio, o stop vai para o preço médio mais offsetPoints (a favor), se for melhor que o stop de agora.
void StopLossAt(double price)Stop de perda num PREÇO (não em pontos). Substitui o stop de agora.
void TakeProfitAt(double price)Alvo num PREÇO. Substitui o alvo de agora.
IReadOnlyList<PendingOrder> PendingOrdersAs pendentes do robô agora (fotografia; a ordem de colocação).
IReadOnlyList<Candle> CandlesOf(string timeframe)Os candles FECHADOS de outro tempo gráfico do mesmo ativo (declare [UsesSeries("15m")] na classe). O tempo do próprio robô devolve Candles. Sem a declaração, ou sem o dado, devolve vazio (e uma recusa SERIE_INDISPONIVEL, uma vez).
IReadOnlyList<Candle> CandlesOf(string symbol, string timeframe)Os candles FECHADOS de outro ativo (declare [UsesSeries("WDOFUT", "5m")]). No backtest, a série pronta que a tela manda (vazia sem histórico dela no período).
IReadOnlyList<Tick> RecentTicksOs últimos negócios (até 500, do mais antigo ao mais novo) desde que o robô ligou. Só ao vivo; no backtest, vazio.
Aggression AggressionA agressão (compra, venda, saldo) desde que o robô ligou. Só ao vivo; no backtest, Zero.
double? SettlementO ajuste do dia (futuros), quando a bolsa divulga. Só ao vivo; no backtest, null.

API · Candles, séries e mercado

Candle

Candle

Um candle fechado. Time é o início do candle em segundos Unix (UTC); a data e a hora em Brasília vêm por Timestamp. End é o fim, quando a barra traz (todos os tempos do gráfico, 01/11/2026).

// compra no candle de alta que fecha acima da máxima do anteriorif (Candles.Count < 2) return;var anterior = Candles[Candles.Count - 2];if (Position.IsFlat && Current.IsBullish && Current.Close > anterior.High) Buy(1);
MembroO que faz
long TimeInício do candle, em segundos Unix (UTC). Nos gráficos atemporais (Renko, Range...), o minuto em que a barra FECHOU (veja End), não o começo dela.
double OpenPreço de abertura, em pontos.
double HighPreço máximo, em pontos.
double LowPreço mínimo, em pontos.
double ClosePreço de fechamento, em pontos.
double VolumeVolume negociado no candle, em contratos.
long EndFim do candle, em segundos Unix (UTC), exclusivo. Nos gráficos temporais o candle vale de Time até antes de End (o de 5 min das 10:00 termina às 10:05; a última barra do pregão pode ser mais curta). 0 quando a barra não diz; aí o fim é o início mais o tempo gráfico (SecondsPerCandle). Nos gráficos atemporais (Renko, Range, Pontos, Ponto e figura, negócios, volume) a barra não tem duração fixa, e End - Time NÃO diz quanto ela levou para se formar: ela é montada dos candles de 1 minuto, Time é o minuto em que ela fechou e End o fim desse minuto (precisão de minuto). As que fecham no mesmo minuto ficam 1 segundo uma depois da outra (a última vai até o fim do minuto). O tempo entre duas barras atemporais, com precisão de minuto, é a diferença entre os End delas. var fim = Current.End > 0 ? Current.End : Current.Time + SecondsPerCandle; // o fim da barra
Timestamp TimestampInício do candle no horário de Brasília (Current.Timestamp.HHMM = 1005 no candle das 10:05).
Date DateA data (em Brasília) do candle. Dois candles com a mesma Date são do mesmo pregão.
double RangeAmplitude do candle em pontos (máxima menos mínima).
bool IsBullishCandle que fechou acima de onde abriu.
bool IsBearishCandle que fechou abaixo de onde abriu.

Negócio

Tick

Um negócio do mercado (ao vivo, cada negócio da bolsa; no backtest, um ponto da lupa de 1m). Aggressor é quem agrediu (comprador = Long); Flat = não informado.

public override void OnTick(Tick tick){    // lote grande comprando a mercado: entra junto    if (Position.IsFlat && tick.Quantity >= 100 && tick.Aggressor == Side.Long) Buy(1);}
MembroO que faz
long TimeMsInstante do negócio, em milissegundos Unix (UTC).
double PricePreço do negócio, em pontos.
int QuantityQuantidade negociada, em contratos.
Side AggressorLado que agrediu; Flat quando não informado.
Timestamp TimestampInstante em Brasília.

Nível do book

BookLevel

Um nível do book: preço, quantidade e número de ordens.

// melhor compra do book (ao vivo)if (Book.BestBid is BookLevel compra && compra.Quantity >= 500)    Log($"{compra.Quantity} contratos em {compra.Price} ({compra.Orders} ordens)");
MembroO que faz
double PricePreço do nível, em pontos.
int QuantityQuantidade somada no nível, em contratos.
int OrdersNúmero de ordens no nível.

Book de ofertas

Book

O book do ativo como chegou da bolsa: compras (do melhor para o pior) e vendas (do melhor para o pior). Vazio quando ainda não chegou nada. Só leitura: é uma fotografia.

public override void OnBook(Book book){    // só entra com spread de um tick e mais compradores que vendedores no topo    if (book.Spread != SymbolInfo.TickSize || book.BestBid is not BookLevel compra || book.BestAsk is not BookLevel venda) return;    if (Position.IsFlat && compra.Quantity > 2 * venda.Quantity) Buy(1);}
MembroO que faz
static readonly Book Empty = new(Array.Empty<BookLevel>(), Array.Empty<BookLevel>())Book vazio: sem compras nem vendas.
Book(IReadOnlyList<BookLevel> bids, IReadOnlyList<BookLevel> asks)Monta o book com as compras e as vendas, cada lado do melhor para o pior preço.
IReadOnlyList<BookLevel> BidsNíveis de compra (bid), do melhor (maior preço) para o pior.
IReadOnlyList<BookLevel> AsksNíveis de venda (ask), do melhor (menor preço) para o pior.
BookLevel? BestBidMelhor compra (bid), ou null sem book.
BookLevel? BestAskMelhor venda (ask), ou null sem book.
double? SpreadDiferença entre a melhor venda e a melhor compra, em pontos; null sem os dois lados.

Período (dia, semana, mês, ano)

Period (enum)

Período de agregação dos candles.

// a semana até agora, a partir da lista de candlesif (Aggregates.UpToCandle(Candles, Candles.Count - 1, Period.Week) is Bar semana)    Log($"semana: máxima {semana.High}, mínima {semana.Low}");
MembroO que faz
DayO dia (pregão).
WeekA semana, começando na segunda-feira.
MonthO mês civil.
YearO ano civil.

Barra de um período

Bar

Um período inteiro resumido (o dia, a semana, o mês ou o ano), montado dos candles do robô: abertura do primeiro candle, máxima e mínima de todos, fechamento do último, volume somado (o OpenD/HighD/LowD/CloseD do NTSL).

// rompeu a máxima de ontem: compraif (PreviousDay is Bar ontem && Position.IsFlat && Current.Close > ontem.High) Buy(1);
MembroO que faz
Timestamp StartInício do período (início do primeiro candle), em Brasília.
double OpenAbertura do primeiro candle, em pontos.
double HighMaior máxima do período, em pontos.
double LowMenor mínima do período, em pontos.
double CloseFechamento do último candle, em pontos.
double VolumeVolume somado do período, em contratos.
int CandlesQuantos candles formam o período.
double RangeMáxima menos mínima.

Agregação por período

Aggregates

Agregação de candles por período (no fuso de Brasília). Só faz contas sobre a lista de candles; não muda nada.

// linha na máxima da semana passadaif (Aggregates.Previous(Candles, Candles.Count - 1, Period.Week) is Bar semana)    HLine(semana.High, "#ffffff", "máxima da semana passada");
MembroO que faz
static Date PeriodKey(Date d, Period p)A chave do período de um dia: dois candles com a mesma chave são do mesmo período.
static Bar? UpToCandle(IReadOnlyList<Candle> candles, int index, Period p)O período do candle index até ele (inclusive): o "dia até agora".
static Bar? Previous(IReadOnlyList<Candle> candles, int index, Period p)O período ANTERIOR ao do candle index, inteiro (o "dia de ontem"); null se não está no histórico.
static bool IsFirstOfDay(IReadOnlyList<Candle> candles, int index)O candle index é o primeiro do seu dia no histórico.

Série

ISeries (interface)

Uma série alinhada aos candles: serie[0] é o valor de agora, serie[1] o do candle anterior (como close[1] no Pine). Fora do histórico, NaN. Todo indicador é uma série; o robô cria as suas com Series; os candles aparecem como séries em Closes, Highs etc. Os utilitários (Ta) valem para qualquer uma.

private static bool SubindoHa3(ISeries s) => s[0] > s[1] && s[1] > s[2];public override void OnBarClose(){    // a mesma função serve para Closes, Highs, um indicador ou uma Series sua    if (Position.IsFlat && SubindoHa3(Closes) && SubindoHa3(Lows)) Buy(1);}
MembroO que faz
double this[int barsAgo]O valor barsAgo candles antes do atual (0 = atual). Fora do histórico, NaN.
int CountQuantos valores existem.

Série própria

Series

Uma série que o próprio robô alimenta, um valor por candle (Add em OnBarClose).

private readonly Series _corpo = new();public override void OnBarClose(){    // corpo do candle duas vezes maior que a média dos últimos 20: alerta    _corpo.Add(Math.Abs(Current.Close - Current.Open));    if (_corpo.Count > 20 && _corpo.Value > 2 * _corpo.Average(20)) Alert("candle de força");}
MembroO que faz
double this[int barsAgo]O valor barsAgo candles antes do atual (0 = atual). Fora do histórico, NaN.
int CountQuantos valores já foram acrescentados.
double ValueO valor de agora (NaN sem valor).
double PreviousO valor do candle anterior.
double Add(double value)Acrescenta o valor deste candle e o devolve.
void ReplaceLast(double value)Troca o valor de agora (o último) sem avançar: para recalcular dentro do mesmo candle.

Série de sim ou não

BoolSeries

Uma série de sim/não alinhada aos candles (Add(cruzou) por candle): responde "há quantos candles foi a última vez" (BarsSince) e "qual era o valor de outra série da última vez" (ValueWhen).

private readonly BoolSeries _rompeu = new();public override void OnBarClose(){    // só compra até 3 candles depois de romper a máxima anterior    _rompeu.Add(Current.Close > Highs[1]);    if (Position.IsFlat && _rompeu.BarsSince() is int n && n <= 3 && Current.IsBullish) Buy(1);}
MembroO que faz
bool this[int barsAgo]O valor barsAgo candles antes do atual (0 = atual). Fora do histórico, false.
int CountQuantos valores já foram acrescentados.
bool ValueO valor de agora (false sem valor).
bool Add(bool value)Acrescenta o valor deste candle e o devolve.
int? BarsSince()Candles desde a última vez verdadeira (0 = agora); null se nunca foi.
double ValueWhen(ISeries series, int occurrence = 0)O valor de series na occurrence-ésima vez (0 = a última) em que o marcador foi verdadeiro; NaN se não houve.

Candles como série

CandleSeries

Os candles vistos como série de um campo (Closes[1]), presos ao índice do candle atual.

// Closes[0] é o fechamento atual, Closes[1] o do candle anteriorif (Position.IsFlat && Closes[0] > Closes.Average(20) && Closes.Rising(3)) Buy(1);if (Position.IsLong && Closes[0] < Lows[1]) ClosePosition();
MembroO que faz
double this[int barsAgo]O campo do candle barsAgo candles antes do atual (0 = atual). Fora do histórico, NaN.
int CountQuantos candles existem até o atual (inclusive).
double ValueO campo do candle atual.
double PreviousO campo do candle anterior.

Contas de série

Ta

Os utilitários de série (o que o Pine tem em ta.* e math.*); NaN quando falta número.

// fechou dois desvios abaixo da média de 20: compra (retorno à média)var media = Ta.Average(Closes, 20);var desvio = Closes.StdDev(20);if (Position.IsFlat && Current.Close < media - 2 * desvio) Buy(1);
MembroO que faz
static double Sum(this ISeries s, int n)A soma dos últimos n valores (contando o atual).
static double Average(this ISeries s, int n)A média dos últimos n valores.
static double StdDev(this ISeries s, int n)O desvio padrão (populacional, como ta.stdev) dos últimos n valores.
static bool Rising(this ISeries s, int n = 1)Subiu n candles seguidos (cada valor maior que o anterior).
static bool Falling(this ISeries s, int n = 1)Caiu n candles seguidos (cada valor menor que o anterior).
static double Change(this ISeries s, int n = 1)A variação em n candles: valor de agora menos o de n atrás.
static double PercentChange(this ISeries s, int n = 1)A variação em n candles, em porcentagem do valor de antes.
static double Percentile(this ISeries s, int n, double p)O percentil p (0 a 100, interpolado) dos últimos n valores.
static double Correlation(this ISeries a, ISeries b, int n)A correlação de Pearson entre as duas séries nos últimos n candles (−1 a 1).

Valor inválido (NaN)

Num

Números com NaN (o na/nz do Pine): o aquecimento dos indicadores é NaN.

// no começo do histórico ainda não há 50 candles: a média vem NaNvar media = Closes.Average(50);if (Num.Na(media)) Log("média de 50 ainda aquecendo");// Nz troca o NaN por outro valor (aqui, o fechamento)Plot("Média 50", Num.Nz(media, Current.Close));
MembroO que faz
static bool Na(double v)O valor não é um número (NaN ou infinito).
static double Nz(double v, double fallback = 0)O valor, ou fallback quando não é um número.

API · Posição e ordens

Lado

Side (enum)

Lado de uma posição ou de uma ordem.

// vendido e o candle fechou de alta: saiif (Position.Side == Side.Short && Current.IsBullish) ClosePosition();

Posição

Position

A posição líquida do robô no ativo (netting, como na B3): uma quantidade com sinal e o preço médio. Quantidade positiva é comprado, negativa é vendido, zero é zerado.

// comprado com 200 pontos a favor: realiza metadeif (Position.IsLong && Position.Contracts >= 2 && Current.Close - Position.AveragePrice >= 200)    ClosePartial(Position.Contracts / 2);Log($"aberto: R$ {Position.OpenProfit(Current.Close, SymbolInfo):0.00}");
MembroO que faz
int QuantityQuantidade com sinal, em contratos: positiva comprado, negativa vendido, zero zerado.
double AveragePricePreço médio da posição, em pontos; 0 quando zerado.
static readonly Position Flat = new(0, 0)Posição zerada.
Side SideO lado da posição: comprado, vendido ou zerado.
bool IsFlatEstá zerado (quantidade zero).
bool IsLongEstá comprado (quantidade positiva).
bool IsShortEstá vendido (quantidade negativa).
int ContractsQuantidade sem sinal.
double OpenPoints(double price)Resultado aberto a um preço, em pontos por contrato vezes a quantidade (sem converter em dinheiro).
double OpenProfit(double price, SymbolInfo symbolInfo)Resultado aberto em dinheiro, pela especificação do contrato.

Tipo de ordem

OrderType (enum)

O tipo de uma ordem do robô. A mercado executa já; as outras ficam PENDENTES até o preço chegar (no dia).

// já tem compra limitada no livro: não põe outraif (PendingOrders.Any(o => o.Type == OrderType.Limit && o.Side == Side.Long)) return;BuyLimit(1, Current.Low - 50, "pullback");
MembroO que faz
MarketA mercado (Buy, Sell, ClosePosition, ClosePartial, Reverse).
LimitLimitada: compra a Price ou menos; vende a ele ou mais. Sem slippage.
StopStop (de entrada ou de saída): o preço tocou o StopPrice, vira ordem a mercado.
StopLimitStop-limite: o preço tocou o gatilho, vira limitada no Price. Só no Simulador (a MT5 recusa).

Ordem pendente

PendingOrder

Uma ordem do robô: a pendente que está no livro (PendingOrders) ou a ordem dos eventos OnOrderRejected/OnOrderCanceled. Name é o que o robô deu (ou o automático, "limite-1", "stop-2"...); a ordem a mercado sem nome vem com "". Price é o limite (limitada e stop-limite) e StopPrice o disparo (stop e stop-limite). ReduceOnly: a ordem só diminui a posição que existia quando foi colocada (uma saída); se a posição zerar, ela cai.

public override void OnOrderCanceled(PendingOrder order, string reason){    // registra qual pendente caiu e por quê    Log($"{order.Name}: {order.Quantity} a {order.Price ?? order.StopPrice} cancelada ({reason})");}
MembroO que faz
string NameNome da ordem (o dado pelo robô ou o automático); "" na ordem a mercado sem nome.
Side SideLado: Long compra, Short vende.
int QuantityQuantidade, em contratos.
OrderType TypeTipo da ordem.
double? PricePreço limite, em pontos (limitada e stop-limite); null nos outros tipos.
double? StopPricePreço de disparo, em pontos (stop e stop-limite); null nos outros tipos.
bool ReduceOnlyA ordem só diminui a posição (uma saída); cai se a posição zerar.
string? Comment = nullComentário livre dado pelo robô; null sem comentário.

Execução

Fill

Uma execução de ordem do robô, entregue em OnFill. Source diz quem mandou: "robo" (a mercado), "stop"/"alvo" (a proteção do motor), "limite", "stop_pendente" e "stop_limite" (as pendentes), "regra", "teto_diario", "fim_do_dia", "fim". Name e Comment são os da ordem (vazio sem nome). No backtest o instante é o INÍCIO do candle em que executou (como as execuções do relatório), ou a hora do ponto quando executou na lupa do OnTick; ao vivo, a hora que a corretora informou.

public override void OnFill(Fill fill){    // a limitada de entrada executou: põe stop e alvo    if (fill.Source == "limite") { StopLoss(150); TakeProfit(300); }    Log($"executou {fill.Quantity} a {fill.Price} às {fill.Time.HHMM}");}
MembroO que faz
Timestamp TimeInstante da execução, em Brasília.
Side SideLado executado: Long comprou, Short vendeu.
int QuantityQuantidade executada, em contratos.
double PricePreço da execução, em pontos.
string SourceQuem mandou a ordem ("robo", "stop", "alvo", "limite", "regra"...).
string Name = ""Nome da ordem; "" sem nome.
string? Comment = nullComentário da ordem; null sem comentário.

Agressão

Aggression

A agressão desde que o robô ligou (só ao vivo): contratos negociados com o comprador agredindo (Buy) e com o vendedor agredindo (Sell). Negócio sem agressor informado não conta. No backtest é sempre Zero (o candle não diz quem agrediu).

// comprador agredindo bem mais que o vendedor (ao vivo)if (Position.IsFlat && Aggression.Delta > 500) Buy(1);Log($"compra {Aggression.Buy}, venda {Aggression.Sell}");
MembroO que faz
long BuyContratos negociados com o comprador agredindo.
long SellContratos negociados com o vendedor agredindo.
static readonly Aggression Zero = new(0, 0)Sem agressão nenhuma (compra e venda zeradas).
long DeltaCompra menos venda: positivo = mais agressão de compra.

Usar outra série

UsesSeriesAttribute

Declara uma série extra que o robô lê com CandlesOf: outro tempo gráfico do mesmo ativo ([UsesSeries("15m")]) ou outro ativo ([UsesSeries("WDOFUT", "5m")]). Tempos: os temporais do gráfico, em minutos (1m a 1439m: 1m, 2m, 5m, 10m, 45m...), em horas (1h a 23h: 2h, 3h, 4h...) ou D; "120m" e "2h" são a mesma série. Séries atemporais (Renko, Range...) ainda não. Até 4 séries e 2 ativos extras por robô. Ao vivo, o robô recebe o histórico e cada candle fechado dessas séries. No backtest (e no indicador do gráfico), a tela manda a série PRONTA, com as barras do gráfico daquele tempo, só as que já fecharam, sempre que o motor não a monta igual dos candles do teste: outro ativo, teste atemporal, tempo que não é múltiplo do tempo do teste e, num teste contado (2m, 10m, 45m...), a série de outra base (2m pedindo 30m). A barra pronta aparece no candle do teste que termina quando ela já terminou (a curta do fim do pregão do mesmo ativo, num teste temporal, no último candle do dia). Outro tempo do MESMO ativo, múltiplo do tempo do teste, é montado dos candles do teste pela regra do gráfico: 5m, 15m, 30m e 60m alinhados ao relógio, como o banco guarda; os outros juntam esses candles contando do início de cada pregão (45m = três de 15m). Sem histórico da série no período do teste (ou com a declaração feita com uma constante, que a tela não lê: escreva o texto), ela fica vazia no backtest, com a recusa SERIE_INDISPONIVEL e o motivo.

[UsesSeries("60m")]public class ATendenciaDo60 : Robot{    public override void OnBarClose()    {        // só compra a favor do último candle de 60 minutos        var h60 = CandlesOf("60m");        if (h60.Count > 0 && h60[h60.Count - 1].IsBullish && Position.IsFlat && Current.IsBullish) Buy(1);    }}
MembroO que faz
UsesSeriesAttribute(string timeframe)Outro tempo gráfico do mesmo ativo do robô.
UsesSeriesAttribute(string symbol, string timeframe)Outro ativo (no tempo gráfico timeframe).
string? SymbolO ativo; null = o do robô.
string TimeframeO tempo gráfico: minutos (1m a 1439m), horas (1h a 23h) ou D.
static readonly IReadOnlyList<string> Timeframes = new[]Os tempos que o banco guarda (1m, 5m, 15m, 30m, 60m e D). Os outros temporais (2m, 45m, 2h...) também valem: são montados destes, como no gráfico (Seconds diz se um texto vale).
const int MaxSeries = 4Quantas séries extras um robô declara, no máximo, e quantos ativos além do dele.
const int MaxExtraSymbols = 2Quantos ativos além do próprio um robô pode declarar, no máximo.
static int Seconds(string? timeframe)A duração do tempo gráfico em segundos (5m = 300, 2h = 7200, D = 86400); 0 para um texto que não é um tempo: minutos de 1 a 1439 ("45m"), horas de 1 a 23 ("2h") ou "D". Sem zero à esquerda; "m" e "h" minúsculos.

API · Ativo, tempo e calendário

Dados do ativo

SymbolInfo

O que o motor precisa saber do contrato para transformar pontos em dinheiro: o tamanho do tick e quanto vale um ponto por contrato. Os números dos futuros da B3 são os mesmos que a plataforma usa no resto do HTS.

// quanto custa um stop de 150 pontos em 2 contratos deste ativovar risco = SymbolInfo.ToMoney(150, 2);Log($"{SymbolInfo.Symbol}: risco de R$ {risco:0.00}");BuyLimit(2, SymbolInfo.RoundToTick(Current.Low - 0.3 * Current.Range), "pullback");
MembroO que faz
string SymbolCódigo do ativo (WINZ26, WDOFUT, PETR4...).
double TickSizeMenor variação de preço, em pontos (5 no WIN, 0,5 no WDO).
double PointValueQuanto vale um ponto por contrato, em reais (0,2 no WIN, 10 no WDO).
string Currency = "BRL"Moeda do resultado; "BRL" por padrão.
static SymbolInfo? FromB3(string symbol)Especificação dos futuros mais operados pela raiz do símbolo (WIN, WDO, IND, DOL) e das ações da B3 (4 letras + 3/4/5/6/7/8/11, com ou sem o F do fracionário: R$ 0,01 de tick, R$ 1 por ponto por ação), a mesma regra da tela de backtest. Outro símbolo devolve null: o motor exige a especificação explícita, nunca chuta.
double RoundToTick(double price)Arredonda um preço para o múltiplo do tick mais próximo.
double ToMoney(double points, int quantity)Quanto vale, em dinheiro, uma diferença de points em quantity contratos.

Dia da semana

Weekday (enum)

Dia da semana, de domingo (0) a sábado (6).

// sexta-feira zera mais cedoif (Today.Weekday == Weekday.Friday && Now.HHMM >= 1700) ClosePosition();

Data

Date

Uma data do calendário (sem hora), no horário de Brasília. É o "pregão" de um candle: dois candles com o mesmo Date são do mesmo dia. Compara com <, > e ==.

// no dia do vencimento do contrato não operavar vencimento = B3Calendar.Expiration(SymbolInfo.Symbol);if (vencimento == Today) return;if (Today.Weekday == Weekday.Monday && Today.Day <= 7) Log("primeira segunda-feira do mês");
MembroO que faz
int YearAno com quatro dígitos.
int MonthMês, de 1 a 12.
int DayDia do mês, de 1 a 31.
Weekday WeekdayO dia da semana desta data.
bool IsWeekendSábado ou domingo.
bool IsBusinessDayDia útil da B3 (sem fim de semana e sem feriado de pregão). Ver B3Calendar.
int WeekOfYearA semana do ano (ISO 8601: a semana começa na segunda; a semana 1 tem a primeira quinta-feira do ano).
int DayOfYearO dia do ano (1 a 366).
Date AddDays(int days)A data days dias corridos depois (negativo = antes).
Date AddMonths(int months)A mesma data months meses depois (o dia é ajustado ao fim do mês quando precisa).
int DaysUntil(Date other)Dias corridos até other (negativo se other é antes).
Date StartOfMonthO primeiro dia do mês desta data.
Date EndOfMonthO último dia do mês desta data.
Date StartOfWeekA segunda-feira da semana desta data.
int CompareTo(Date other)Compara com outra data: negativo se esta é antes, zero se é a mesma, positivo se é depois.
override string ToString()"dd/MM/aaaa".
string Iso"aaaa-MM-dd" (formato ISO).
static Date? FromIso(string? text)Lê "aaaa-MM-dd"; null se não é uma data válida.

Instante

Timestamp

Um instante, mostrado no horário de Brasília (com o horário de verão de 2008 a 2019, para o backtest antigo; sem horário de verão desde 2019). O robô não lê relógio: o instante vem SEMPRE do mercado — o início ou o fim de um candle, a hora de um negócio. Ver Now e Timestamp.

// zera às 17:50 e não abre antes das 9:15if (Now.HHMM >= 1750) { ClosePosition(); return; }if (Now.HHMM < 915) return;
MembroO que faz
long MillisecondsO instante em milissegundos Unix (UTC).
static Timestamp FromSeconds(long unixSeconds)A partir de segundos Unix (UTC) — o Time do candle.
Date DateA data (em Brasília).
int YearO ano, em Brasília.
int MonthO mês (1 a 12), em Brasília.
int DayO dia do mês (1 a 31), em Brasília.
int HourA hora (0 a 23), em Brasília.
int MinuteO minuto (0 a 59).
int SecondO segundo (0 a 59).
Weekday WeekdayO dia da semana, em Brasília.
int HHMMHora e minuto num número: 9:05 = 905, 17:50 = 1750 (o Time do NTSL).
int MinuteOfDayMinutos desde a meia-noite (0 a 1439).
long UnixSecondsSegundos Unix (UTC), o mesmo número do Time do candle.
bool Between(int hhmmStart, int hhmmEnd)Entre dois horários do dia, em HHMM: inclui o início e exclui o fim (Between(900, 1200) = das 9h às 11:59).
Timestamp AddSeconds(long seconds)O instante seconds segundos depois (negativo = antes).
Timestamp AddMinutes(long minutes)O instante minutes minutos depois (negativo = antes).
long MinutesUntil(Timestamp other)Minutos (inteiros) até other; negativo se for antes.
int CompareTo(Timestamp other)Compara com outro instante: negativo se este é antes, zero se é o mesmo, positivo se é depois.
override string ToString()"dd/MM/aaaa HH:mm:ss".

Calendário da B3

B3Calendar

O calendário de pregão da B3: dias úteis, feriados e vencimentos. Os feriados seguem a regra oficial (Ofício Circular da B3 de cada ano): os nacionais fixos, Carnaval (segunda e terça), Sexta-feira Santa e Corpus Christi (pela Páscoa), Consciência Negra (20/11, desde 2024), e os dias sem sessão de 24/12 e 31/12. Os feriados municipais de São Paulo (25/01, 09/07) têm pregão desde 2022. Quarta-feira de Cinzas tem pregão, a partir das 13h.

if (!Today.IsBusinessDay) return;var du = B3Calendar.BusinessDaysBetween(Today, B3Calendar.Expiration("WINZ26")!.Value);if (du <= 1) { ClosePosition(); return; } // não carregar no dia do vencimento
MembroO que faz
static string? HolidayName(Date d)O nome do feriado (ou dia sem pregão) nesta data; null se não é feriado. Fim de semana não é feriado.
static bool IsBusinessDay(Date d)Dia com pregão: não é fim de semana nem feriado.
static Date NextBusinessDay(Date d)O primeiro dia útil DEPOIS de d.
static Date PreviousBusinessDay(Date d)O último dia útil ANTES de d.
static Date BusinessDayOrNext(Date d)d se for dia útil; senão, o próximo dia útil.
static int BusinessDaysBetween(Date from, Date until)Dias úteis entre duas datas, como no mercado (ANBIMA): conta from e não conta until. Do mesmo dia = 0; de hoje até amanhã útil = 1. Negativo se until é antes.
static Date? NthBusinessDayOfMonth(int year, int month, int n)O n-ésimo dia útil do mês (1 = o primeiro); null se o mês não tem tantos.
static Date LastBusinessDayOfMonth(int year, int month)O último dia útil do mês.
static int? SpecialOpening(Date d)A abertura especial do dia em HHMM (Quarta-feira de Cinzas: 1300); null = horário normal.
static Date? Expiration(string symbol)O vencimento de um contrato futuro da B3 pelo código (WINZ26, WDOX26, INDZ26, DOLX26, DI1F27); null se o ativo não é um desses ou o código não tem mês/ano. WIN e IND (meses pares): a quarta-feira mais próxima do dia 15; se não for dia útil, o próximo dia útil; WDO, DOL e DI1: o primeiro dia útil do mês do contrato.
static int? BusinessDaysToExpiration(string symbol, Date today)Dias úteis de today até o vencimento do contrato (0 = vence hoje); null se não se sabe o vencimento.
static string? CurrentContract(string root, Date today)O código do contrato vigente de uma raiz ("WIN", "WDO"...) numa data: o primeiro que vence DEPOIS dela — no dia do vencimento a plataforma já vira para o próximo. Ex.: CurrentContract("WIN", new Date(2026, 10, 30)) = "WINZ26".
static Date? NextExpiration(string root, Date today)O vencimento do contrato vigente da raiz ("WIN", "WDO"...) numa data: a data em que ele vence, sempre DEPOIS de today. null se a raiz não é conhecida.
const string MonthLetters = "FGHJKMNQUVXZ"F G H J K M N Q U V X Z = janeiro a dezembro (o padrão da B3).
static Date Easter(int year)O domingo de Páscoa do ano (algoritmo de Meeus/Jones/Butcher, calendário gregoriano).

API · Regras e resultado

Estado do pregão

SessionState (enum)

O estado do pregão do ativo, informado pela bolsa (ao vivo). No backtest é sempre Unknown.

// em leilão não abre posiçãoif (Session == SessionState.Auction) return;if (Position.IsFlat && Current.IsBullish) Buy(1);
MembroO que faz
UnknownEstado não informado (sempre assim no backtest).
OpenPregão aberto, em negociação contínua.
AuctionLeilão: de abertura, intradiário ou de fechamento.
ClosedPregão fechado: sem negociação.

Regras da automação

AutomationRules

As regras da automação, escolhidas na tela "Meus robôs" e vigiadas pelo MOTOR: o robô lê (Rules), mas não precisa nem consegue burlar. Regra nunca bloqueia saída. Horário em HHMM de Brasília (1740 = 17:40); dinheiro em reais; null = sem a regra. StartTime/NoEntryAfter: a janela de entrada; FlattenAt: zera e encerra o dia; PauseInAuction: não abre com o ativo em leilão; WaitAfterOpen: não abre nos primeiros N minutos do pregão (desde o primeiro candle do dia); DailyTarget/DailyStop: realizado + aberto do dia atinge → zera e encerra o dia; MaxConsecutiveLosses: N fechamentos seguidos com perda → zera e encerra o dia; MaxEntriesPerDay: entradas (a partir de zerada) por dia; MaxPosition: contratos, em módulo.

// fora da janela de entrada da tela, nem tentaif (!Rules.CanEnterAt(Now.HHMM) || !Rules.OpeningWaitPassed(MinutesSinceOpen)) return;var maximo = Rules.MaxPosition ?? 1;if (Position.Contracts < maximo && Current.IsBullish) Buy(1);
MembroO que faz
int? StartTime = nullInício da janela de entrada, em HHMM de Brasília; null sem a regra.
int? NoEntryAfter = nullNão abre posição a partir deste horário, em HHMM de Brasília; null sem a regra.
int? FlattenAt = nullZera e encerra o dia neste horário, em HHMM de Brasília; null sem a regra.
bool PauseInAuction = falseNão abre posição com o ativo em leilão.
double? DailyTarget = nullMeta do dia, em reais (realizado + aberto); null sem a regra.
double? DailyStop = nullStop do dia, em reais (realizado + aberto); null sem a regra.
int? MaxConsecutiveLosses = nullFechamentos seguidos com perda que encerram o dia; null sem a regra.
int? MaxEntriesPerDay = nullEntradas (a partir de zerado) permitidas por dia; null sem a regra.
int? MaxPosition = nullPosição máxima, em contratos (em módulo); null sem a regra.
int? WaitAfterOpen = nullMinutos sem abrir posição depois do primeiro candle do dia; null sem a regra.
static readonly AutomationRules None = new()Sem nenhuma regra.
bool CanEnterAt(int hhmm)O horário hhmm está dentro da janela de entrada (início, não abrir depois, zerar às).
bool OpeningWaitPassed(int? minutesSinceOpen)Já passou a espera da abertura. minutesSinceOpen null (nenhum candle hoje) não passa: sem saber a abertura, não abre.

Operação fechada

Trade

Uma operação fechada (de zerado a zerado, ou até a virada de mão). Tempos em segundos Unix. Dinheiro pela especificação do contrato; Mfe/Mae são a maior excursão a favor (≥ 0) e contra (≤ 0) enquanto a operação esteve aberta (pela máxima/mínima dos candles no backtest; pelos negócios ao vivo).

// depois de uma perda, espera o próximo candle de alta para voltarvar ultima = LastTrade;if (ultima is not null && ultima.Profit < 0 && !Current.IsBullish) return;if (ultima is not null) Log($"última: {ultima.Points} pontos, R$ {ultima.Profit:0.00}");
MembroO que faz
long EntryTimeInstante da entrada, em segundos Unix.
long ExitTimeInstante da saída, em segundos Unix.
Side SideLado da operação: Long comprada, Short vendida.
int ContractsQuantidade da operação, em contratos.
double EntryPricePreço médio de entrada, em pontos.
double ExitPricePreço médio de saída, em pontos.
double GrossProfitResultado antes da corretagem, em reais.
double CommissionCorretagem da operação, em reais.
double ProfitResultado líquido (bruto menos corretagem), em reais.
string ExitReasonMotivo da saída (quem mandou a ordem que zerou).
double Mfe = 0Maior excursão a favor enquanto aberta, em reais (≥ 0).
double Mae = 0Maior excursão contra enquanto aberta, em reais (≤ 0).
double PointsPontos por contrato no sentido da operação (positivo = ganhou).

Resultado da automação

Pnl

O resultado da automação, só leitura. Day é o realizado de hoje (no backtest já com corretagem; ao vivo, o realizado do robô na conta); Open é a posição ao preço de agora; Total é o realizado desde o início (do backtest; ao vivo, desde que o robô foi ligado). Drawdown e runup são a maior queda e a maior subida de DayWithOpen no dia, em dinheiro (≥ 0).

// ganhou R$ 300 no dia (realizado + aberto): zera e para de entrarif (Pnl.DayWithOpen >= 300) { ClosePosition(); return; }Log($"dia: R$ {Pnl.Day:0.00}, aberto: R$ {Pnl.Open:0.00}");
MembroO que faz
double DayRealizado de hoje, em reais.
double OpenResultado da posição aberta ao preço de agora, em reais.
double TotalRealizado desde o início, em reais.
double DayDrawdownMaior queda do realizado + aberto no dia, em reais (≥ 0).
double DayRunupMaior subida do realizado + aberto no dia, em reais (≥ 0).
static readonly Pnl Zero = new(0, 0, 0, 0, 0)Resultado zerado em todos os campos.
double DayWithOpenRealizado do dia mais o aberto: é o que a meta e o stop diário olham.

API · Gráfico

Estilo do desenho

PlotStyle (enum)

Como uma série plotada por Plot é desenhada no gráfico. A cor padrão pode vir do código (StylePlot), e o gráfico deixa trocar na "Aparência".

// volume como histograma e a média dele como linhaPlot("Volume", Current.Volume, PlotStyle.Histogram);Plot("Volume médio", Volumes.Average(20), PlotStyle.Line);
MembroO que faz
LineLinha contínua ligando os valores (o padrão).
HistogramHistograma: uma barra por candle.
PointsUm ponto em cada candle com valor.
AreaLinha com a área até a base preenchida.
StepLinha em degraus (o valor vale até o próximo candle).
CrossUma cruz em cada candle com valor.
ColumnsColunas a partir do zero, na largura do candle.

Posição da marca

MarkerPosition (enum)

Onde a marca fica em relação ao candle.

// seta verde abaixo do candle que rompeu a máxima anteriorif (Current.Close > Highs[1]) Mark("rompeu", MarkerPosition.Below, MarkerShape.Arrow, "#22c55e");
MembroO que faz
AboveAcima da máxima (ou do valor dado).
BelowAbaixo da mínima (ou do valor dado).

Forma da marca

MarkerShape (enum)

A forma da marca: seta apontando para o candle, ponto, ou só o texto.

// ponto acima de todo candle sem corpo (doji)if (Math.Abs(Current.Close - Current.Open) <= SymbolInfo.TickSize) Mark("doji", MarkerPosition.Above, MarkerShape.Dot);
MembroO que faz
ArrowSeta apontando para o candle.
DotUm ponto.
TextSó o texto, sem forma.

Nível do registro

LogLevel (enum)

O nível de um registro do robô: Info é o Log de sempre; Alert é o Alert(...), que no HTS vira aviso na tela (toast, som e sino) e marca no gráfico.

// perto do stop diário: registra como avisoif (Pnl.DayWithOpen < -200) Log("perto do stop diário", LogLevel.Warning);
MembroO que faz
InfoInformação: o Log de sempre.
WarningAviso: algo merece atenção, mas o robô segue.
ErrorErro registrado pelo robô.
AlertAlerta (Alert(...)): aviso na tela (toast, som e sino) e marca no gráfico.

Sobre o preço

OverlayAttribute

Na classe do indicador: as séries plotadas vão SOBRE o preço (média, banda, VWAP), na escala do preço. Sem o atributo, o indicador ganha um painel próprio com escala livre (MACD, RSI, oscilador).

[Overlay]public class MediaDe20 : Robot{    // a média aparece em cima dos candles, na escala do preço    public override void OnBarClose() => Plot("Média 20", Closes.Average(20));}

API · Parâmetros

Formato do parâmetro

ParameterFormat (enum)

O formato de um parâmetro de texto ou de hora: diz à tela que campo mostrar e ao motor o que aceitar. Time vale para int (HHMM, 1740 = 17:40; a tela mostra HH:MM); os outros para string.

[Parameter("Zerar às", Format = ParameterFormat.Time)] public int ZerarAs = 1740;[Parameter("Cor da média", Format = ParameterFormat.Color)] public string Cor = "#22c55e";public override void OnBarClose(){    if (Now.HHMM >= ZerarAs) ClosePosition();    Plot("Média 20", Closes.Average(20), Cor);}
MembroO que faz
DefaultO campo comum do tipo (número, caixa de marcar, texto ou lista).
Timeint em HHMM; a tela digita HH:MM.
Colorstring com cor #rrggbb; a tela mostra o seletor de cor.
Symbolstring com o código do ativo (WINZ26, WDOFUT); a tela mostra a busca de ativo.
Timeframestring com o tempo gráfico (1m, 5m, 15m, 30m, 60m, D); a tela mostra a lista.

Parâmetro

ParameterAttribute

Marca um campo ou propriedade pública do robô como parâmetro ajustável pela tela, dentro dos limites definidos aqui. Tipos aceitos: int, double, bool, string (texto; com Options vira lista) e qualquer enum seu (lista de opções pelo nome).

[Parameter("Período da média curta", Min = 2, Max = 200, Step = 1, Group = "Médias")]public int PeriodoCurto = 9;public enum Modo { Tendencia, Reversao }[Parameter("Modo")] public Modo ModoDeOperacao = Modo.Tendencia;[Parameter("Zerar às", Format = ParameterFormat.Time)] public int ZerarAs = 1740;
MembroO que faz
ParameterAttribute(string name)Marca o parâmetro com o name mostrado na tela.
string NameNome mostrado na tela.
string? DescriptionExplicação curta, opcional.
double MinMenor valor aceito (ignorado em bool, texto e lista).
double MaxMaior valor aceito (ignorado em bool, texto e lista).
double StepO passo do campo numérico na tela (0,5; 1; 5...). Só ajuda a digitar; não arredonda.
string? GroupO grupo em que a tela agrupa os parâmetros ("Médias", "Risco"...).
string[]? OptionsPara string: as opções aceitas; o campo vira uma lista (só entra o que está aqui).
ParameterFormat FormatO formato (hora, cor, ativo, tempo gráfico); Default = o do tipo.

API · Indicadores

Amplitude média (ATR)

Atr

ATR de Wilder sobre o true range. O aquecimento é a média simples dos primeiros N true ranges e só então entra a suavização recursiva, como no gráfico da HTS: é assim que o número bate com o das outras plataformas. O primeiro candle (sem anterior) conta com true range = máxima − mínima.

private Atr atr = null!;private Ema media = null!;public override void OnStart() { atr = new Atr(14); media = new Ema(21); }public override void OnBarClose(){    atr.Update(Current);    media.Update(Current.Close);    // stop de 2 ATRs na entrada    if (atr.IsReady && Position.IsFlat && Crossed.Above(Closes, media)) { Buy(); StopLoss(2 * atr.Value); }}
MembroO que faz
Atr(int period)Cria o ATR com period candles (1 a 500).
int PeriodO período (em candles).
static double TrueRange(Candle current, Candle? previous)True range de um candle dado o anterior (ou só a amplitude, sem anterior).
double Update(Candle candle)Avança com o candle fechado e devolve o ATR novo (NaN no aquecimento).

Bandas de Bollinger

Bollinger

Bandas de Bollinger: média simples no meio e bandas a Multiplier desvios-padrão (populacional) de distância. A conta é a do gráfico da HTS: desvio-padrão populacional dos últimos N valores. Value é a média; as bandas ficam em Upper e Lower.

private Bollinger bandas = null!;public override void OnStart() { bandas = new Bollinger(20, 2); }public override void OnBarClose(){    bandas.Update(Current.Close);    if (!bandas.IsReady) return;    // volta à média: compra abaixo da banda inferior, zera na média    if (Position.IsFlat && Current.Close < bandas.Lower) Buy();    else if (Position.IsLong && Current.Close >= bandas.Middle) ClosePosition();}
MembroO que faz
Bollinger(int period, double multiplier = 2)Cria as bandas com média de period candles e bandas a multiplier desvios-padrão (0,1 a 10).
int PeriodO período (em candles).
double MultiplierQuantos desvios-padrão separam cada banda da média.
double MiddleA média (o mesmo que Value).
double UpperA banda superior no candle atual (NaN no aquecimento).
double LowerA banda inferior no candle atual (NaN no aquecimento).
double UpperAgo(int barsAgo)A banda superior barsAgo candles atrás (0 = agora).
double LowerAgo(int barsAgo)A banda inferior barsAgo candles atrás (0 = agora).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a média nova (NaN no aquecimento); as bandas avançam junto.

Saída de um indicador

Output

Uma saída secundária de indicador (banda, sinal, histograma), com histórico alinhado aos candles.

private Keltner canal = null!;public override void OnStart() { canal = new Keltner(20, 10, 2); }public override void OnBarClose(){    canal.Update(Current);    // a banda superior é uma série: dá para ler o histórico e cruzar    Output superior = canal.UpperSeries;    if (Position.IsFlat && Crossed.Above(Closes, superior)) Buy();}
MembroO que faz
double this[int barsAgo]O valor barsAgo candles atrás (0 = agora). Fora do histórico, NaN.
int CountQuantos valores já foram calculados (contando os NaN do aquecimento).
double ValueO valor no candle atual (NaN no aquecimento).
double PreviousO valor no candle anterior.

Canal de Keltner

Keltner

Canal de Keltner: EMA do fechamento no meio e bandas a Multiplier·ATR, como o Keltner no gráfico. A média (Value) existe desde o primeiro candle; as bandas ficam NaN enquanto o ATR aquece (N − 1 candles do período do ATR).

private Keltner canal = null!;public override void OnStart() { canal = new Keltner(20, 10, 2); }public override void OnBarClose(){    canal.Update(Current);    if (double.IsNaN(canal.Upper)) return;    // rompimento da banda de cima, com stop na média    if (Position.IsFlat && Current.Close > canal.Upper) { Buy(); StopLoss(Current.Close - canal.Middle); }}
MembroO que faz
Keltner(int period = 20, int atrPeriod = 10, double multiplier = 2)Cria o canal com EMA de period candles, ATR de atrPeriod candles e bandas a multiplier·ATR (0,1 a 20).
int PeriodO período da EMA do meio (em candles).
int AtrPeriodO período do ATR que dá a largura das bandas (em candles).
double MultiplierQuantos ATRs separam cada banda da média.
double MiddleA média (o mesmo que Value).
double UpperA banda superior no candle atual (NaN no aquecimento).
double LowerA banda inferior no candle atual (NaN no aquecimento).
double UpperAgo(int barsAgo)A banda superior barsAgo candles atrás (0 = agora).
double LowerAgo(int barsAgo)A banda inferior barsAgo candles atrás (0 = agora).
Output UpperSeriesA banda superior como série (para Crossed e os utilitários de série).
Output LowerSeriesA banda inferior como série (para Crossed e os utilitários de série).
double Update(Candle candle)Avança com o candle fechado e devolve a média nova; as bandas avançam junto (NaN enquanto o ATR aquece).

Canal de Donchian

Donchian

Canal de Donchian: a maior máxima e a menor mínima dos últimos N candles (contando o atual) e o meio entre as duas, como o Donchian no gráfico. Value é o Middle. NaN até ter N candles.

private Donchian canal = null!;public override void OnStart() { canal = new Donchian(20); }public override void OnBarClose(){    canal.Update(Current);    // tartaruga: compra no rompimento da máxima dos 20 candles anteriores, sai no meio do canal    if (Position.IsFlat && Current.Close > canal.UpperAgo(1)) Buy();    else if (Position.IsLong && Current.Close < canal.Middle) ClosePosition();}
MembroO que faz
Donchian(int period = 20)Cria o canal com period candles (1 a 500).
int PeriodO período (em candles).
double MiddleO meio do canal (o mesmo que Value).
double UpperA maior máxima dos últimos N candles (NaN no aquecimento).
double LowerA menor mínima dos últimos N candles (NaN no aquecimento).
double UpperAgo(int barsAgo)A banda superior barsAgo candles atrás (0 = agora).
double LowerAgo(int barsAgo)A banda inferior barsAgo candles atrás (0 = agora).
ISeries UpperSeriesA máxima do canal como série (para Crossed).
ISeries LowerSeriesA mínima do canal como série (para Crossed).
double Update(Candle candle)Avança com o candle fechado (máxima e mínima) e devolve o meio do canal novo (NaN no aquecimento).

Envelope de média

Envelope

Envelope: média simples com bandas a Percent% acima e abaixo, como o Envelope no gráfico. Value é a média. NaN até ter N valores.

private Envelope envelope = null!;public override void OnStart() { envelope = new Envelope(20, 0.5); }public override void OnBarClose(){    envelope.Update(Current.Close);    if (!envelope.IsReady) return;    // esticou 0,5% acima da média: vende buscando a volta    if (Position.IsFlat && Current.Close > envelope.Upper) Sell();    else if (Position.IsShort && Current.Close <= envelope.Middle) ClosePosition();}
MembroO que faz
Envelope(int period = 20, double percent = 2)Cria o envelope com média de period candles e bandas a percent% da média (acima de 0 até 100).
int PeriodO período da média (em candles).
double PercentA distância de cada banda à média, em % da média.
double MiddleA média (o mesmo que Value).
double UpperA banda superior no candle atual (NaN no aquecimento).
double LowerA banda inferior no candle atual (NaN no aquecimento).
double UpperAgo(int barsAgo)A banda superior barsAgo candles atrás (0 = agora).
double LowerAgo(int barsAgo)A banda inferior barsAgo candles atrás (0 = agora).
Output UpperSeriesA banda superior como série (para Crossed e os utilitários de série).
Output LowerSeriesA banda inferior como série (para Crossed e os utilitários de série).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a média nova (NaN no aquecimento); as bandas avançam junto.

Cruzamento

Crossed

Cruzamentos entre duas séries (indicador, Series, Closes...), ou entre uma série e um nível fixo. Um cruzamento só existe quando os dois valores (de agora e do candle anterior) são números: no aquecimento a resposta é sempre false.

private readonly Ema _rapida = new(9);private readonly Ema _lenta = new(21);public override void OnBarClose(){    _rapida.Update(Current);    _lenta.Update(Current);    if (Position.IsFlat && Crossed.Above(_rapida, _lenta)) Buy(1);    else if (Position.IsLong && Crossed.Below(_rapida, _lenta)) ClosePosition();}
MembroO que faz
static bool Above(ISeries a, ISeries b)a estava abaixo ou igual a b e agora está acima.
static bool Below(ISeries a, ISeries b)a estava acima ou igual a b e agora está abaixo.
static bool Above(ISeries a, double level)A série estava abaixo ou igual ao nível e agora está acima.
static bool Below(ISeries a, double level)A série estava acima ou igual ao nível e agora está abaixo.
static bool Above(double aBefore, double aNow, double bBefore, double bNow)Cruzou para cima com valores avulsos: a estava abaixo ou igual a b antes e agora está acima.
static bool Below(double aBefore, double aNow, double bBefore, double bNow)Cruzou para baixo com valores avulsos: a estava acima ou igual a b antes e agora está abaixo.

Heikin-Ashi

HeikinAshi

Heikin-Ashi: os candles "médios", um por candle de verdade. Fechamento = (A + M + m + F) / 4; abertura = média da abertura e do fechamento do Heikin-Ashi anterior (o primeiro usa (A + F) / 2 do candle real); máxima e mínima incluem a abertura e o fechamento novos. Value é o fechamento HA; o candle inteiro está em Current e o histórico em CandleAgo. O tempo e o volume são os do candle real.

private HeikinAshi ha = null!;public override void OnStart() { ha = new HeikinAshi(); }public override void OnBarClose(){    ha.Update(Current);    // primeiro candle Heikin-Ashi de alta depois de um de baixa: compra    if (ha.CandleAgo(1) is Candle anterior && ha.IsBullish && anterior.IsBearish && Position.IsFlat) Buy();    else if (Position.IsLong && !ha.IsBullish) ClosePosition();}
MembroO que faz
Candle? CurrentO candle Heikin-Ashi de agora; null antes do primeiro.
Candle? CandleAgo(int barsAgo)O candle Heikin-Ashi barsAgo candles antes (0 = agora); null fora do histórico.
IReadOnlyList<Candle> CandlesTodos os candles Heikin-Ashi até agora (para passar a outro indicador, por exemplo).
bool IsBullishO candle de agora é de alta (fechamento HA acima da abertura HA).
double Update(Candle candle)Avança com o candle real fechado, monta o candle Heikin-Ashi correspondente e devolve o fechamento HA.

Tijolo do Renko

Brick

Um tijolo do Renko: de onde saiu, até onde foi, o lado e o candle (tempo) em que fechou.

private Renko renko = null!;public override void OnStart() { renko = new Renko(100); }public override void OnBarClose(){    renko.Update(Current);    // o último tijolo fechado: lado e preços    if (renko.NewBricks > 0 && renko.Last is Brick tijolo)        Log($"Tijolo {tijolo.Side}: {tijolo.Open} a {tijolo.Close}");}
MembroO que faz
double OpenO preço em que o tijolo começa.
double CloseO preço em que o tijolo termina.
Side SideO lado do tijolo: Long de alta, Short de baixa.
long TimeO início, em segundos Unix, do candle em que o tijolo fechou.

Renko

Renko

Renko: tijolos de tamanho fixo em pontos sobre o FECHAMENTO dos candles. Um tijolo novo no mesmo sentido precisa andar Size além do topo (ou fundo) do último; a reversão precisa de 2 × tamanho (a regra clássica: o tijolo contrário começa do outro lado do último). Um candle pode fechar vários tijolos (ou nenhum). Value é o fechamento do último tijolo, repetido nos candles sem tijolo novo; NewBricks diz quantos fecharam neste candle.

private Renko renko = null!;public override void OnStart() { renko = new Renko(100); }public override void OnBarClose(){    renko.Update(Current);    // virada do Renko de 100 pontos: segue o lado do tijolo novo    if (renko.FlippedNow && renko.Direction == Side.Long) { ClosePosition(); Buy(); }    else if (renko.FlippedNow && renko.Direction == Side.Short) { ClosePosition(); Sell(); }}
MembroO que faz
Renko(double size)Cria o Renko com tijolos de size pontos (positivo).
double SizeO tamanho do tijolo, em pontos.
IReadOnlyList<Brick> BricksOs tijolos fechados até agora, do mais antigo ao mais novo.
Brick? LastO último tijolo; null antes do primeiro.
int NewBricksQuantos tijolos fecharam no último candle.
Side DirectionO lado do último tijolo (Flat antes do primeiro).
bool FlippedNowVirou de lado neste candle (o primeiro tijolo do candle é contrário ao último de antes).
double Update(Candle candle)Avança com o candle fechado (o fechamento e o tempo) e devolve o fechamento do último tijolo (NaN antes do primeiro).
double Update(double price, long time = 0)Avança com um preço price (um por candle) e o tempo time gravado nos tijolos que fecharem; devolve o fechamento do último tijolo (NaN antes do primeiro).

Máxima de N candles

Highest

A maior máxima dos últimos N candles (contando o atual). NaN até ter N candles.

private Highest maxima = null!;public override void OnStart() { maxima = new Highest(20); }public override void OnBarClose(){    maxima.Update(Current);    // rompimento: fechou acima da maior máxima dos 20 candles anteriores    if (Position.IsFlat && Current.Close > maxima[1]) Buy();}
MembroO que faz
Highest(int period)Cria o indicador com period candles (1 a 500).
int PeriodO período (em candles).
double Update(Candle candle)Avança com o candle fechado (a máxima) e devolve a maior máxima nova (NaN no aquecimento).

Mínima de N candles

Lowest

A menor mínima dos últimos N candles (contando o atual). NaN até ter N candles.

private Lowest minima = null!;public override void OnStart() { minima = new Lowest(10); }public override void OnBarClose(){    minima.Update(Current);    // saída da compra: fechou abaixo da menor mínima dos 10 candles anteriores    if (Position.IsLong && Current.Close < minima[1]) ClosePosition();}
MembroO que faz
Lowest(int period)Cria o indicador com period candles (1 a 500).
int PeriodO período (em candles).
double Update(Candle candle)Avança com o candle fechado (a mínima) e devolve a menor mínima nova (NaN no aquecimento).

Ichimoku

Ichimoku

Ichimoku Kinko Hyo: Tenkan (meio da faixa de 9), Kijun (meio da faixa de 26), Senkou A (média das duas) e Senkou B (meio da faixa de 52), as duas últimas desenhadas 26 candles À FRENTE, e Chikou (o fechamento de agora, desenhado 26 candles ATRÁS). Mesma conta do Ichimoku no gráfico; o deslocamento é o período do Kijun, como no sistema original. Para o robô, o que importa é a nuvem SOB O CANDLE ATUAL: SenkouA e SenkouB são os valores calculados 26 candles atrás, que é onde o gráfico os desenha hoje ("preço acima da nuvem" = Close > Math.Max(SenkouA, SenkouB)). SenkouAFuture e SenkouBFuture são os calculados agora, a nuvem daqui a 26 candles. Chikou é o fechamento de agora e CloseAtChikou o fechamento de 26 candles atrás, que é com quem o Chikou se compara no gráfico. Value é o Tenkan.

private Ichimoku ichi = null!;public override void OnStart() { ichi = new Ichimoku(9, 26, 52); }public override void OnBarClose(){    ichi.Update(Current);    // Tenkan cruzou o Kijun para cima com o preço acima da nuvem    if (Position.IsFlat && Current.Close > ichi.CloudTop && Crossed.Above(ichi, ichi.KijunSeries))        Buy(1);}
MembroO que faz
Ichimoku(int tenkan = 9, int kijun = 26, int senkou = 52)Cria o Ichimoku com as faixas do Tenkan (tenkan), do Kijun (kijun, também o deslocamento) e do Senkou B (senkou), em candles.
int TenkanPeriodA faixa do Tenkan, em candles.
int KijunPeriodA faixa do Kijun, em candles (também o deslocamento).
int SenkouPeriodA faixa do Senkou B, em candles.
int DisplacementQuantos candles a nuvem é jogada à frente e o Chikou para trás (= período do Kijun).
double TenkanO Tenkan (o mesmo que Value).
double KijunO Kijun (meio da faixa de KijunPeriod candles).
double SenkouASenkou A sob o candle atual (calculado Displacement candles atrás).
double SenkouBSenkou B sob o candle atual.
double SenkouAFutureSenkou A calculado agora (a nuvem daqui a Displacement candles).
double SenkouBFutureSenkou B calculado agora (a nuvem daqui a Displacement candles).
double ChikouO fechamento de agora (o gráfico o desenha Displacement candles atrás).
double CloseAtChikouO fechamento de Displacement candles atrás: o preço sob o Chikou.
double CloudTopO topo da nuvem sob o candle atual.
double CloudBottomA base da nuvem sob o candle atual.
double TenkanAgo(int barsAgo)O Tenkan barsAgo candles atrás (0 = agora).
double KijunAgo(int barsAgo)O Kijun barsAgo candles atrás (0 = agora).
double SenkouAAgo(int barsAgo)O Senkou A sob o candle de barsAgo candles atrás (0 = sob o atual, como SenkouA).
double SenkouBAgo(int barsAgo)O Senkou B sob o candle de barsAgo candles atrás (0 = sob o atual, como SenkouB).
Output KijunSeriesO Kijun como série (para Crossed e os utilitários de série).
Output SenkouAFutureSeriesO Senkou A como série, alinhado ao candle em que foi CALCULADO (sem o deslocamento à frente).
Output SenkouBFutureSeriesO Senkou B como série, alinhado ao candle em que foi CALCULADO (sem o deslocamento à frente).
Output CloseSeriesOs fechamentos como série (a base do Chikou).
double Update(Candle candle)Recebe o candle fechado e devolve o Tenkan novo (NaN no aquecimento); Kijun, Senkou A/B e Chikou são atualizados junto.

Indicador (base)

Indicator

Base dos indicadores: uma série que avança um valor por candle e guarda o histórico, para o robô comparar o valor de agora com o de candles atrás (media[1] é o do candle anterior). Durante o aquecimento o valor é NaN, exatamente como no gráfico da HTS. Todo indicador é uma ISeries: os utilitários de série (Average(n), Highest(n), Rising(n)...) valem para ele.

private readonly Ema _media = new(21);public override void OnBarClose(){    _media.Update(Current);    // média pronta e subindo, preço acima dela: compra    if (_media.IsReady && _media.Value > _media[1] && Current.Close > _media.Value && Position.IsFlat) Buy(1);}
MembroO que faz
double ValueO valor no candle atual (NaN no aquecimento).
double PreviousO valor no candle anterior.
double this[int barsAgo]O valor barsAgo candles antes do atual (0 = atual). Fora do histórico, NaN.
int CountQuantos valores já foram calculados (contando os NaN do aquecimento).
bool IsReadyO indicador já saiu do aquecimento (o valor atual é um número).

Indicador de um valor (base)

ValueIndicator

Indicador alimentado por um valor por candle (por padrão, o fechamento).

private readonly Sma _mediaDoMeio = new(20);public override void OnBarClose(){    // Update aceita o candle (usa o fechamento) ou qualquer número    _mediaDoMeio.Update((Current.High + Current.Low) / 2);    if (_mediaDoMeio.IsReady) Plot("Média do meio", _mediaDoMeio.Value);}
MembroO que faz
abstract double Update(double value)Avança um candle com um valor qualquer (fechamento, outro indicador, etc.).
double Update(Candle candle)Avança um candle usando o fechamento.

Média exponencial

Ema

Média móvel exponencial com k = 2 / (N + 1). Semeia com o primeiro valor válido e devolve esse valor já no primeiro candle, como a EMA do gráfico da HTS: os primeiros valores carregam o peso da semente. Valor não numérico não avança a média (devolve a anterior).

private Ema rapida = null!;private Ema lenta = null!;public override void OnStart() { rapida = new Ema(9); lenta = new Ema(21); }public override void OnBarClose(){    rapida.Update(Current.Close);    lenta.Update(Current.Close);    // cruzamento clássico das médias 9 e 21    if (Crossed.Above(rapida, lenta)) Buy();    else if (Crossed.Below(rapida, lenta)) Sell();}
MembroO que faz
Ema(int period)Cria a média exponencial com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a média nova; valor que não é número devolve a anterior.

Média móvel simples

Sma

Média móvel simples: a média aritmética dos últimos N valores. NaN até ter N valores, e NaN se algum valor da janela não for número (mesma regra do gráfico da HTS).

private Sma media = null!;public override void OnStart() { media = new Sma(20); }public override void OnBarClose(){    media.Update(Current.Close);    // só desenha a média quando o fechamento está acima dela    if (media.IsReady && Current.Close > media.Value) Plot("Média", media.Value);}
MembroO que faz
Sma(int period)Cria a média simples com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a média nova (NaN no aquecimento).

Média ponderada

Wma

Média móvel ponderada (WMA): o candle mais recente pesa N, o anterior N − 1, e assim por diante. NaN até ter N valores e NaN se algum valor da janela não é número (mesma conta do WMA no gráfico).

private Wma media = null!;public override void OnStart() { media = new Wma(21); }public override void OnBarClose(){    media.Update(Current.Close);    // compra quando o fechamento cruza a média para cima    if (Position.IsFlat && Crossed.Above(Closes, media)) Buy();}
MembroO que faz
Wma(int period)Cria a WMA com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a WMA nova (NaN no aquecimento).

Média de Hull

Hma

Média de Hull (HMA): WMA(√N) de [2·WMA(N/2) − WMA(N)], a conta do HMA no gráfico (N/2 arredondado para baixo, √N arredondado para o inteiro mais próximo). Aquecimento: N + √N − 2 candles de NaN.

private Hma hull = null!;public override void OnStart() { hull = new Hma(16); }public override void OnBarClose(){    hull.Update(Current.Close);    if (!hull.IsReady) return;    // verde subindo, vermelha caindo    Plot("Hull", hull.Value, hull.Value > hull.Previous ? "#22c55e" : "#ef4444");}
MembroO que faz
Hma(int period)Cria a média de Hull com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a HMA nova (NaN no aquecimento).

Média de Wilder

Rma

Média de Wilder (RMA/SMMA, a que roda por dentro do RSI e do ATR): semeia com a média simples dos primeiros N valores e depois avança por (anterior·(N − 1) + valor)/N, como o SMMA no gráfico. NaN nos N − 1 primeiros candles. Valor não numérico devolve a média anterior sem avançar.

private Rma amplitude = null!;public override void OnStart() { amplitude = new Rma(14); }public override void OnBarClose(){    // média de Wilder da amplitude dos candles    amplitude.Update(Current.High - Current.Low);    if (amplitude.IsReady && Current.Range > 2 * amplitude.Value) Log("Candle esticado: o dobro da amplitude média");}
MembroO que faz
Rma(int period)Cria a média de Wilder com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a média nova (NaN no aquecimento).

Média ponderada por volume

Vwma

Média ponderada por volume (VWMA): Σ(fechamento·volume)/Σ(volume) nos últimos N candles, como o VWMA no gráfico. Precisa do candle (volume), por isso só tem Update. NaN até ter N candles e quando o volume da janela é zero.

private Vwma porVolume = null!;private Sma simples = null!;public override void OnStart() { porVolume = new Vwma(20); simples = new Sma(20); }public override void OnBarClose(){    porVolume.Update(Current);    simples.Update(Current.Close);    // VWMA acima da média simples: o volume está do lado comprador    if (porVolume.IsReady && simples.IsReady && porVolume.Value > simples.Value) Plot("VWMA", porVolume.Value);}
MembroO que faz
Vwma(int period)Cria a VWMA com period candles (1 a 500).
int PeriodO período (em candles).
double Update(Candle candle)Avança com o candle fechado (fechamento e volume) e devolve a VWMA nova (NaN no aquecimento).

Média de Arnaud Legoux (ALMA)

Alma

ALMA (Arnaud Legoux): pesos em curva de sino com o centro em offset·(N − 1) e largura N/sigma, como o ALMA no gráfico. NaN até ter N valores.

private Alma alma = null!;public override void OnStart() { alma = new Alma(21, 0.85, 6); }public override void OnBarClose(){    alma.Update(Current.Close);    // zera a compra quando o fechamento perde a ALMA    if (Position.IsLong && Crossed.Below(Closes, alma)) ClosePosition();}
MembroO que faz
Alma(int period, double offset = 0.85, double sigma = 6)Cria o ALMA com period candles, o centro dos pesos em offset (0 a 1; perto de 1 favorece os candles recentes) e a largura da curva dada por sigma (maior = curva mais estreita).
int PeriodO período (em candles).
double OffsetOnde fica o centro dos pesos na janela, de 0 (o candle mais antigo) a 1 (o mais recente).
double SigmaO sigma da curva de pesos (a largura é N/sigma; maior = pesos mais concentrados no centro). Mínimo 0,1.
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve o ALMA novo (NaN no aquecimento).

Média adaptativa de Kaufman (KAMA)

Kama

KAMA (Kaufman): a velocidade da suavização vem da eficiência do movimento (quanto o preço andou em linha reta contra o caminho total nos últimos N candles), entre as EMAs de fastPeriod e slowPeriod. Mesma conta do KAMA no gráfico: NaN nos N primeiros candles (a semente é o fechamento do N-ésimo) e o primeiro valor sai no candle N + 1.

private Kama kama = null!;public override void OnStart() { kama = new Kama(10, 2, 30); }public override void OnBarClose(){    kama.Update(Current.Close);    if (!kama.IsReady) return;    // KAMA parada = mercado lateral; só compra com ela subindo    if (Position.IsFlat && kama.Value > kama.Previous && Current.Close > kama.Value) Buy();}
MembroO que faz
Kama(int period, int fastPeriod = 2, int slowPeriod = 30)Cria o KAMA com eficiência medida em period candles, variando entre a EMA de fastPeriod (movimento eficiente) e a de slowPeriod (mercado lateral).
int PeriodO período da medida de eficiência (em candles).
int FastO período da EMA rápida, usada quando o preço anda em linha reta.
int SlowO período da EMA lenta, usada quando o preço anda de lado.
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve o KAMA novo (NaN no aquecimento).

Média exponencial dupla

Dema

DEMA: 2·EMA − EMA(EMA), como o DEMA no gráfico. Tem valor desde o primeiro candle (as EMAs semeiam com o primeiro valor) e converge ao longo dos primeiros candles.

private Dema rapida = null!;private Dema lenta = null!;public override void OnStart() { rapida = new Dema(9); lenta = new Dema(21); }public override void OnBarClose(){    rapida.Update(Current.Close);    lenta.Update(Current.Close);    // cruzamento de duas DEMAs    if (Crossed.Above(rapida, lenta)) Buy();    else if (Crossed.Below(rapida, lenta)) Sell();}
MembroO que faz
Dema(int period)Cria a DEMA com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a DEMA nova; valor que não é número devolve a anterior.

Média exponencial tripla

Tema

TEMA: 3·EMA − 3·EMA(EMA) + EMA(EMA(EMA)), como o TEMA no gráfico. Valor desde o primeiro candle.

private Tema tema = null!;public override void OnStart() { tema = new Tema(20); }public override void OnBarClose(){    tema.Update(Current.Close);    Plot("TEMA", tema.Value);    // vende quando o fechamento perde a TEMA    if (Position.IsFlat && Crossed.Below(Closes, tema)) Sell();}
MembroO que faz
Tema(int period)Cria a TEMA com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve a TEMA nova; valor que não é número devolve a anterior.

TRIX

Trix

TRIX: variação percentual (em pontos-base, ×10 000) da EMA tripla de um candle para o outro, como o TRIX no gráfico. NaN só no primeiro candle.

private Trix trix = null!;public override void OnStart() { trix = new Trix(15); }public override void OnBarClose(){    trix.Update(Current.Close);    // TRIX cruzando o zero para cima: a tendência virou de alta    if (Position.IsFlat && Crossed.Above(trix, 0)) Buy();    else if (Position.IsLong && Crossed.Below(trix, 0)) ClosePosition();}
MembroO que faz
Trix(int period)Cria o TRIX com period candles em cada uma das três EMAs (1 a 500).
int PeriodO período de cada EMA (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve o TRIX novo (NaN no primeiro candle e quando o valor não é número).

Média T3 de Tillson

T3

T3 (Tillson): seis EMAs encadeadas combinadas pelo fator de volume factor, como o T3 no gráfico. Valor desde o primeiro candle; converge ao longo do aquecimento.

private T3 t3 = null!;public override void OnStart() { t3 = new T3(8, 0.7); }public override void OnBarClose(){    t3.Update(Current.Close);    // compra com o fechamento acima da T3 e a T3 subindo    if (Position.IsFlat && Current.Close > t3.Value && t3.Value > t3.Previous) Buy();    Plot("T3", t3.Value);}
MembroO que faz
T3(int period, double factor = 0.7)Cria o T3 com period candles em cada EMA e o fator de volume factor (0 a 1; com 0 o T3 vira a EMA da EMA da EMA).
int PeriodO período de cada EMA (em candles).
double FactorO fator de volume (0 a 1) que combina as EMAs encadeadas.
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve o T3 novo; valor que não é número devolve o anterior.

Série deslocada

Shifted

Uma série vista com deslocamento: Shifted(media, 5)[0] é o valor que media tinha 5 candles atrás (a média "deslocada para a frente" do gráfico, o offset do Pine). Não copia nada: lê a série original na hora, então vale para qualquer indicador ou Series. Deslocamento negativo não existe (seria ler o futuro).

private Sma media = null!;private Shifted deslocada = null!;public override void OnStart() { media = new Sma(20); deslocada = new Shifted(media, 3); }public override void OnBarClose(){    media.Update(Current.Close);    // compra quando o fechamento cruza a média deslocada 3 candles    if (Position.IsFlat && Crossed.Above(Closes, deslocada)) Buy();}
MembroO que faz
Shifted(ISeries source, int offset)Lê source com offset candles de atraso (0 a 5000).
int ShiftO deslocamento (em candles).
double this[int barsAgo]O valor da série deslocada barsAgo candles atrás (0 = agora), ou seja, o da fonte barsAgo + Shift candles atrás.
int CountQuantos valores a série deslocada tem (os da fonte menos o deslocamento).
double ValueO valor deslocado no candle atual.
double PreviousO valor deslocado no candle anterior.

Índice de fluxo de dinheiro (MFI)

Mfi

MFI (Money Flow Index): o RSI com volume. Fluxo = preço típico × volume; soma dos fluxos dos candles em que o típico subiu contra os em que caiu, nos últimos N candles, de 0 a 100. Mesma conta do MFI no gráfico: a comparação precisa do candle anterior, então o primeiro valor sai no candle N + 1 (N candles de NaN).

private Mfi mfi = null!;public override void OnStart() { mfi = new Mfi(14); }public override void OnBarClose(){    mfi.Update(Current);    // pouco dinheiro entrando (abaixo de 20): compra; excesso (acima de 80): zera    if (Position.IsFlat && mfi.Value < 20) Buy(1);    else if (Position.IsLong && mfi.Value > 80) ClosePosition();}
MembroO que faz
Mfi(int period = 14)Cria o MFI com period candles (padrão 14).
int PeriodO período (em candles).
double Update(Candle candle)Recebe o candle fechado (usa máxima, mínima, fechamento e volume) e devolve o MFI novo, de 0 a 100 (NaN no aquecimento).

Oscilador de momento de Chande (CMO)

Cmo

CMO (Chande): (Σ altas − Σ baixas)/(Σ altas + Σ baixas) × 100 nas últimas N variações, de −100 a 100, sem alisamento, como o CMO no gráfico. Primeiro valor no candle N + 1.

private Cmo cmo = null!;public override void OnStart() { cmo = new Cmo(14); }public override void OnBarClose(){    cmo.Update(Current.Close);    // abaixo de −50 é sobrevenda; acima de +50, sobrecompra    if (Position.IsFlat && cmo.Value < -50) Buy(1);    else if (Position.IsLong && cmo.Value > 50) ClosePosition();}
MembroO que faz
Cmo(int period = 14)Cria o CMO com period variações (padrão 14).
int PeriodO período (em candles).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o CMO novo, de −100 a 100 (NaN no aquecimento).

Taxa de variação (ROC)

Roc

ROC: variação percentual entre o valor de agora e o de N candles atrás, como o ROC no gráfico. NaN nos N primeiros candles e quando o valor de referência é zero.

private Roc roc = null!;public override void OnStart() { roc = new Roc(12); }public override void OnBarClose(){    roc.Update(Current.Close);    Plot("ROC %", roc.Value, PlotStyle.Histogram);    // a variação em 12 candles virou positiva: compra    if (Position.IsFlat && Crossed.Above(roc, 0)) Buy(1);}
MembroO que faz
Roc(int period = 12)Cria o ROC comparando com o valor de period candles atrás (padrão 12).
int PeriodO período (em candles).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o ROC novo, em % (NaN no aquecimento).

Momento

Momentum

Momentum: o valor de agora menos o de N candles atrás, em pontos, como o Momentum no gráfico. NaN nos N primeiros candles.

private Momentum mom = null!;public override void OnStart() { mom = new Momentum(10); }public override void OnBarClose(){    mom.Update(Current.Close);    // momento cruzou o zero: compra para cima, zera para baixo    if (Position.IsFlat && Crossed.Above(mom, 0)) Buy(1);    else if (Position.IsLong && Crossed.Below(mom, 0)) ClosePosition();}
MembroO que faz
Momentum(int period = 10)Cria o Momentum comparando com o valor de period candles atrás (padrão 10).
int PeriodO período (em candles).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o Momentum novo, em pontos (NaN no aquecimento).

Índice de força verdadeira (TSI)

Tsi

TSI (True Strength Index): a variação do preço alisada por duas EMAs (longa e depois curta), dividida pelo valor absoluto da variação alisado do mesmo jeito, × 100. Mesma conta do TSI no gráfico: as EMAs semeiam com a primeira variação, então o valor existe desde o segundo candle e converge.

private Tsi tsi = null!;public override void OnStart() { tsi = new Tsi(25, 13); }public override void OnBarClose(){    tsi.Update(Current.Close);    Plot("TSI", tsi.Value);    // TSI cruzou o zero: compra para cima, zera para baixo    if (Position.IsFlat && Crossed.Above(tsi, 0)) Buy(1);    else if (Position.IsLong && Crossed.Below(tsi, 0)) ClosePosition();}
MembroO que faz
Tsi(int longPeriod = 25, int shortPeriod = 13)Cria o TSI com a EMA longa de longPeriod e a curta de shortPeriod candles.
int LongPeriodO período da primeira EMA (a longa), em candles.
int ShortPeriodO período da segunda EMA (a curta), em candles.
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o TSI novo, de −100 a 100 (NaN no primeiro candle).

Oscilador final

UltimateOscillator

Ultimate Oscillator (Larry Williams): pressão compradora (fechamento − mínimo entre a mínima e o fechamento anterior) sobre a amplitude verdadeira, em três janelas combinadas com pesos 4, 2 e 1, de 0 a 100. Mesma conta do Ultimate Oscillator no gráfico. NaN até ter Long candles.

private UltimateOscillator uo = null!;public override void OnStart() { uo = new UltimateOscillator(7, 14, 28); }public override void OnBarClose(){    uo.Update(Current);    // abaixo de 30 é sobrevenda; acima de 70, sobrecompra    if (Position.IsFlat && uo.Value < 30) Buy(1);    else if (Position.IsLong && uo.Value > 70) ClosePosition();}
MembroO que faz
UltimateOscillator(int shortPeriod = 7, int mediumPeriod = 14, int longPeriod = 28)Cria o oscilador com as janelas curta (shortPeriod), média (mediumPeriod) e longa (longPeriod), em candles.
int ShortA janela curta (peso 4), em candles.
int MediumA janela média (peso 2), em candles.
int LongA janela longa (peso 1), em candles.
double Update(Candle candle)Recebe o candle fechado e devolve o Ultimate Oscillator novo, de 0 a 100 (NaN no aquecimento).

Níveis de pivô

PivotLevels

Os sete níveis de um pivô.

Bar? ontem = PreviousDay;if (ontem is not null){    PivotLevels p = Pivots.Classic(ontem.Value);    // desenha o pivô e a primeira resistência e suporte do dia    Plot("PP", p.PP);    Plot("R1", p.R1);    Plot("S1", p.S1);}
MembroO que faz
double PPO pivô central.
double R1A primeira resistência (a mais perto, acima).
double R2A segunda resistência.
double R3A terceira resistência (a mais longe, acima).
double S1O primeiro suporte (o mais perto, abaixo).
double S2O segundo suporte.
double S3O terceiro suporte (o mais longe, abaixo).

Pivôs

Pivots

Pivôs calculados da máxima, mínima e fechamento do período ANTERIOR (o dia de ontem, a semana passada), com as mesmas fórmulas do Pivot do gráfico. Você passa os números (normalmente de PreviousDay, ou Aggregates.Previous(Candles, Candles.Count - 1, Period.Day)).

Bar? ontem = PreviousDay;if (ontem is not null){    PivotLevels p = Pivots.Classic(ontem.Value);    // rompeu a R1 de baixo para cima: compra mirando a R2, stop no pivô    if (Position.IsFlat && Closes[1] <= p.R1 && Current.Close > p.R1)    {        Buy(1);        TakeProfitAt(p.R2);        StopLossAt(p.PP);    }}
MembroO que faz
static PivotLevels Classic(double high, double low, double close)Clássico: PP = (H + L + C)/3; R1 = 2PP − L; R2 = PP + (H − L); R3 = H + 2(PP − L); e os suportes espelhados.
static PivotLevels Fibonacci(double high, double low, double close)Fibonacci: PP = (H + L + C)/3 e níveis a 38,2%, 61,8% e 100% da amplitude.
static PivotLevels Camarilla(double high, double low, double close)Camarilla: níveis apertados em volta do FECHAMENTO (C ± amplitude × 1,1/12, /6 e /4); PP = (H + L + C)/3.
static PivotLevels Classic(Bar previousPeriod)Pivô clássico a partir da máxima, mínima e fechamento de previousPeriod.
static PivotLevels Fibonacci(Bar previousPeriod)Pivô Fibonacci a partir da máxima, mínima e fechamento de previousPeriod.
static PivotLevels Camarilla(Bar previousPeriod)Pivô Camarilla a partir da máxima, mínima e fechamento de previousPeriod.

Topos e fundos

Swings

Topos e fundos confirmados: o candle cuja máxima supera estritamente a dos Left candles antes e dos Right candles depois é um topo (idem, espelhado, para o fundo), a regra dos fractais do gráfico com lados independentes. A confirmação chega com Right candles de atraso: em HighConfirmedNow o topo é o candle de Right candles atrás, e LastHigh passa a valer o preço dele. Highs e Lows são séries alinhadas ao candle da CONFIRMAÇÃO (o preço do extremo, ou NaN).

private Swings swings = null!;public override void OnStart() { swings = new Swings(2, 2); }public override void OnBarClose(){    swings.Update(Current);    // confirmou um fundo mais alto que o anterior: compra com stop abaixo dele    if (Position.IsFlat && swings.LowConfirmedNow && swings.LastLow > swings.PreviousLow)    {        Buy(1);        StopLossAt(swings.LastLow - 5);    }}
MembroO que faz
Swings(int left = 2, int right = 2)Cria o detector com left candles de comparação antes e right depois do extremo (1 a 500 cada).
int LeftQuantos candles antes do extremo ele precisa superar.
int RightQuantos candles depois do extremo ele precisa superar (é o atraso da confirmação).
double LastHighO preço do último topo confirmado (NaN se ainda não houve).
double LastLowO preço do último fundo confirmado.
double PreviousHighO topo confirmado antes do último (para "topo mais alto que o anterior").
double PreviousLowO fundo confirmado antes do último (para "fundo mais baixo que o anterior").
bool HighConfirmedNowNeste candle confirmou-se um topo (o de Right candles atrás).
bool LowConfirmedNowNeste candle confirmou-se um fundo (o de Right candles atrás).
int BarsSinceHighHá quantos candles está o último topo (0 = o atual; −1 se não houve).
int BarsSinceLowHá quantos candles está o último fundo (0 = o atual; −1 se não houve).
ISeries HighsSérie dos topos no candle em que foram confirmados (preço ou NaN).
ISeries LowsSérie dos fundos no candle em que foram confirmados (preço ou NaN).
void Update(Candle candle)Recebe o candle fechado e verifica se ele confirma um topo ou fundo de Right candles atrás.

Regressão linear

LinearRegression

Regressão linear dos últimos N valores: Value é o valor da reta no candle atual (a LSMA e o canal de regressão do gráfico), Slope é a taxa por candle e R2 o quanto a reta explica, de 0 a 1. Forecast estende a reta para a frente (com 1 é a EPMA). NaN até ter N valores.

private LinearRegression reg = null!;public override void OnStart() { reg = new LinearRegression(20); }public override void OnBarClose(){    reg.Update(Current.Close);    Plot("LSMA", reg.Value);    // reta subindo e bem ajustada: tendência de alta limpa    if (Position.IsFlat && reg.Slope > 0 && reg.R2 > 0.7) Buy(1);}
MembroO que faz
LinearRegression(int period = 20)Cria a regressão com os últimos period valores (padrão 20).
int PeriodO período (em candles).
double SlopeA inclinação da reta: quanto ela anda por candle.
double InterceptO valor da reta no candle mais antigo da janela (x = 0).
double R2O R² da reta, de 0 a 1 (quanto ela explica dos valores).
double SlopeAgo(int barsAgo)A inclinação barsAgo candles atrás (0 = agora).
double R2Ago(int barsAgo)O R² barsAgo candles atrás (0 = agora).
Output SlopeSeriesA inclinação como série (para Crossed e os utilitários de série).
Output R2SeriesO R² como série (para Crossed e os utilitários de série).
double Forecast(int barsAhead)O valor da reta barsAhead candles depois do atual (0 = o próprio Value).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o valor da reta no candle atual (NaN no aquecimento).

Canal de regressão

RegressionChannel

Canal de regressão: a reta de mínimos quadrados no meio (Value) e bandas a Deviations erros-padrão dos resíduos (√(Σ(y − reta)²/(N − 2)), as bandas de erro padrão do gráfico). Precisa de N ≥ 3. NaN até ter N valores.

private RegressionChannel canal = null!;public override void OnStart() { canal = new RegressionChannel(50, 2); }public override void OnBarClose(){    canal.Update(Current.Close);    // fechou abaixo da banda de baixo: compra mirando o meio do canal    if (Position.IsFlat && Current.Close < canal.Lower) Buy(1);    else if (Position.IsLong && Current.Close >= canal.Value) ClosePosition();}
MembroO que faz
RegressionChannel(int period = 50, double deviations = 2)Cria o canal com os últimos period valores (pelo menos 3) e bandas a deviations erros-padrão.
int PeriodO período (em candles).
double DeviationsA quantos erros-padrão as bandas ficam da reta.
double SlopeA inclinação da reta: quanto ela anda por candle.
double StandardErrorO erro-padrão dos resíduos (a largura de um desvio).
double UpperA banda de cima (reta + desvios × erro-padrão).
double LowerA banda de baixo (reta − desvios × erro-padrão).
double UpperAgo(int barsAgo)A banda de cima barsAgo candles atrás (0 = agora).
double LowerAgo(int barsAgo)A banda de baixo barsAgo candles atrás (0 = agora).
Output UpperSeriesA banda de cima como série (para Crossed e os utilitários de série).
Output LowerSeriesA banda de baixo como série (para Crossed e os utilitários de série).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve a reta no candle atual (NaN no aquecimento); as bandas são atualizadas junto.

Estocástico

Stochastic

Estocástico: %K é a posição do fechamento na faixa máxima–mínima dos últimos KPeriod candles, alisada por média simples de KSmoothing; %D é a média simples de DPeriod do %K. Cobre o rápido (suavização 1), o lento (3) e o completo. Mesma conta do Estocástico no gráfico: faixa zero é NaN, não 50. Value é o %K; o %D fica em D.

private Stochastic sto = null!;public override void OnStart() { sto = new Stochastic(14, 3, 3); }public override void OnBarClose(){    sto.Update(Current);    // %K cruzou o %D para cima na região de sobrevenda (abaixo de 20)    if (Position.IsFlat && sto.K < 20 && Crossed.Above(sto, sto.DSeries)) Buy(1);    else if (Position.IsLong && sto.K > 80) ClosePosition();}
MembroO que faz
Stochastic(int kPeriod = 14, int kSmoothing = 3, int dPeriod = 3)Cria o Estocástico com a faixa de kPeriod candles, o %K alisado por kSmoothing e o %D de dPeriod.
int KPeriodQuantos candles entram na faixa máxima–mínima do %K.
int KSmoothingA média simples que alisa o %K (1 = Estocástico rápido).
int DPeriodO período da média simples do %D.
double KO %K (o mesmo que Value).
double DO %D (a linha de sinal).
double DAgo(int barsAgo)O %D barsAgo candles atrás (0 = agora).
Output DSeriesO %D como série (para Crossed e os utilitários de série).
double Update(Candle candle)Recebe o candle fechado e devolve o %K novo, de 0 a 100 (NaN no aquecimento); o %D é atualizado junto.

Estocástico do IFR

StochasticRsi

Estocástico do RSI: a posição do RSI na própria faixa dos últimos StochasticPeriod valores, alisada como o Estocástico. Mesma conta do Estocástico RSI no gráfico, inclusive o RSI de dentro, que semeia com a média simples das primeiras N variações (diferente de Rsi, que converge de zero): o primeiro RSI sai no candle N + 1. Value é o %K.

private StochasticRsi srsi = null!;public override void OnStart() { srsi = new StochasticRsi(14, 14, 3, 3); }public override void OnBarClose(){    srsi.Update(Current);    // saiu da sobrecompra (%K cruzou 80 para baixo): vende    if (Position.IsFlat && Crossed.Below(srsi, 80)) Sell(1);    else if (Position.IsShort && srsi.K < 20) ClosePosition();}
MembroO que faz
StochasticRsi(int rsiPeriod = 14, int stochasticPeriod = 14, int kSmoothing = 3, int dPeriod = 3)Cria o Estocástico do RSI: RSI de rsiPeriod, faixa de stochasticPeriod valores, %K alisado por kSmoothing e %D de dPeriod.
int RsiPeriodO período do RSI de dentro, em candles.
int StochasticPeriodQuantos valores do RSI entram na faixa máxima–mínima.
int KSmoothingA média simples que alisa o %K.
int DPeriodO período da média simples do %D.
double KO %K (o mesmo que Value).
double DO %D (a linha de sinal).
double DAgo(int barsAgo)O %D barsAgo candles atrás (0 = agora).
Output DSeriesO %D como série (para Crossed e os utilitários de série).
double InnerRsiO RSI de dentro (semeado pela média simples, como no gráfico).
Output RsiSeriesO RSI de dentro como série (para Crossed e os utilitários de série).
double Update(double close)Recebe o fechamento e devolve o %K novo, de 0 a 100 (NaN no aquecimento); o %D e o RSI de dentro são atualizados junto.
double Update(Candle candle)O mesmo que Update com o fechamento do candle.

MACD

Macd

MACD: EMA rápida − EMA lenta (Value), a EMA de SignalPeriod dessa diferença (Signal) e a diferença entre as duas (Histogram). Mesma conta do MACD no gráfico: as três EMAs semeiam com o primeiro valor, então há número desde o primeiro candle (zero) e ele converge ao longo do aquecimento.

private Macd macd = null!;public override void OnStart() { macd = new Macd(12, 26, 9); }public override void OnBarClose(){    macd.Update(Current.Close);    Plot("Histograma", macd.Histogram, PlotStyle.Histogram);    // linha do MACD cruzou a de sinal para cima: compra; para baixo: zera    if (Position.IsFlat && Crossed.Above(macd, macd.SignalSeries)) Buy(1);    else if (Position.IsLong && Crossed.Below(macd, macd.SignalSeries)) ClosePosition();}
MembroO que faz
Macd(int fastPeriod = 12, int slowPeriod = 26, int signal = 9)Cria o MACD com a EMA rápida de fastPeriod, a lenta de slowPeriod e o sinal de signal candles.
int FastPeriodO período da EMA rápida, em candles.
int SlowPeriodO período da EMA lenta, em candles.
int SignalPeriodO período da EMA da linha de sinal, em candles.
double LineA linha MACD (o mesmo que Value).
double SignalA linha de sinal (EMA da linha MACD).
double HistogramO histograma (linha MACD − sinal).
double SignalAgo(int barsAgo)A linha de sinal barsAgo candles atrás (0 = agora).
double HistogramAgo(int barsAgo)O histograma barsAgo candles atrás (0 = agora).
Output SignalSeriesA linha de sinal como série (para Crossed e os utilitários de série).
Output HistogramSeriesO histograma como série (para Crossed e os utilitários de série).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve a linha MACD nova (NaN se o valor não é número); sinal e histograma são atualizados junto.

Índice de canal de commodities (CCI)

Cci

CCI (Lambert): (preço típico − média do típico)/(0,015 · desvio médio absoluto) nos últimos N candles, como CCI no gráfico. NaN até ter N candles e quando o desvio é zero.

private Cci cci = null!;public override void OnStart() { cci = new Cci(20); }public override void OnBarClose(){    cci.Update(Current);    // voltou de baixo de −100: compra; passou de +100: zera    if (Position.IsFlat && Crossed.Above(cci, -100)) Buy(1);    else if (Position.IsLong && cci.Value > 100) ClosePosition();}
MembroO que faz
Cci(int period = 20)Cria o CCI com period candles (padrão 20).
int PeriodO período (em candles).
double Update(Candle candle)Recebe o candle fechado e devolve o CCI novo (NaN no aquecimento).

Williams %R

WilliamsR

Williams %R: (maior máxima − fechamento)/(faixa) × −100 nos últimos N candles, de −100 a 0, como o Williams %R no gráfico. NaN até ter N candles e com faixa zero.

private WilliamsR wr = null!;public override void OnStart() { wr = new WilliamsR(14); }public override void OnBarClose(){    wr.Update(Current);    // abaixo de −80 é sobrevenda; acima de −20, sobrecompra    if (Position.IsFlat && wr.Value < -80) Buy(1);    else if (Position.IsLong && wr.Value > -20) ClosePosition();}
MembroO que faz
WilliamsR(int period = 14)Cria o Williams %R com period candles (padrão 14).
int PeriodO período (em candles).
double Update(Candle candle)Recebe o candle fechado e devolve o %R novo, de −100 a 0 (NaN no aquecimento).

Padrões de candle

Patterns

Padrões de candle, com os MESMOS critérios do catálogo de padrões do gráfico (régua da TA-Lib): corpo e sombras são medidos contra a média dos 10 candles anteriores ao PRIMEIRO candle do padrão (precisa de pelo menos 5), e a tendência que antecede o padrão separa martelo de enforcado e estrela cadente de martelo invertido (tendência = fechamento do candle anterior ao padrão menos a média dos 5 fechamentos antes dele). Sem contexto suficiente, nenhum padrão casa. Todo método recebe a lista de candles e o índice do ÚLTIMO candle do padrão; sem índice, o último da lista (Patterns.Hammer(Candles, Candles.Count - 1) em OnBarClose).

// martelo ou engolfo de alta depois de queda: compra com stop e alvo em pontosif (Position.IsFlat && (Patterns.Hammer(Candles) || Patterns.BullishEngulfing(Candles))){    Buy(1);    StopLoss(150);    TakeProfit(300);}
MembroO que faz
static bool Doji(IReadOnlyList<Candle> candles, int i)Corpo de até 10% da amplitude média (indecisão).
static bool Doji(IReadOnlyList<Candle> candles)Doji no último candle da lista (o mesmo que passar o índice candles.Count − 1).
static bool Hammer(IReadOnlyList<Candle> candles, int i)Corpo pequeno no topo, sombra inferior de pelo menos 2 corpos, quase sem sombra superior, DEPOIS DE QUEDA (alta).
static bool Hammer(IReadOnlyList<Candle> candles)Martelo no último candle da lista.
static bool HangingMan(IReadOnlyList<Candle> candles, int i)A mesma forma do martelo DEPOIS DE ALTA (baixa).
static bool HangingMan(IReadOnlyList<Candle> candles)Enforcado no último candle da lista.
static bool InvertedHammer(IReadOnlyList<Candle> candles, int i)Corpo pequeno embaixo, sombra superior de pelo menos 2 corpos, DEPOIS DE QUEDA (alta).
static bool InvertedHammer(IReadOnlyList<Candle> candles)Martelo invertido no último candle da lista.
static bool ShootingStar(IReadOnlyList<Candle> candles, int i)A mesma forma do martelo invertido DEPOIS DE ALTA (baixa).
static bool ShootingStar(IReadOnlyList<Candle> candles)Estrela cadente no último candle da lista.
static bool BullishMarubozu(IReadOnlyList<Candle> candles, int i)Candle de alta com corpo longo e quase sem sombras.
static bool BullishMarubozu(IReadOnlyList<Candle> candles)Marubozu de alta no último candle da lista.
static bool BearishMarubozu(IReadOnlyList<Candle> candles, int i)Candle de baixa com corpo longo e quase sem sombras.
static bool BearishMarubozu(IReadOnlyList<Candle> candles)Marubozu de baixa no último candle da lista.
static bool Marubozu(IReadOnlyList<Candle> candles, int i)Marubozu de qualquer lado.
static bool Marubozu(IReadOnlyList<Candle> candles)Marubozu de qualquer lado no último candle da lista.
static bool BullishEngulfing(IReadOnlyList<Candle> candles, int i)Depois de queda, candle de baixa seguido de candle de alta cujo corpo engole o anterior.
static bool BullishEngulfing(IReadOnlyList<Candle> candles)Engolfo de alta terminando no último candle da lista.
static bool BearishEngulfing(IReadOnlyList<Candle> candles, int i)Depois de alta, candle de alta seguido de candle de baixa cujo corpo engole o anterior.
static bool BearishEngulfing(IReadOnlyList<Candle> candles)Engolfo de baixa terminando no último candle da lista.
static bool BullishHarami(IReadOnlyList<Candle> candles, int i)Depois de queda, candle de baixa longo seguido de candle de alta menor, com o corpo dentro do anterior.
static bool BullishHarami(IReadOnlyList<Candle> candles)Harami de alta terminando no último candle da lista.
static bool BearishHarami(IReadOnlyList<Candle> candles, int i)Depois de alta, candle de alta longo seguido de candle de baixa menor, com o corpo dentro do anterior.
static bool BearishHarami(IReadOnlyList<Candle> candles)Harami de baixa terminando no último candle da lista.
static bool MorningStar(IReadOnlyList<Candle> candles, int i)Depois de queda: baixa longa, corpo curto abaixo dela (com gap no corpo) e alta fechando acima do meio da primeira. Vale também com doji no meio.
static bool MorningStar(IReadOnlyList<Candle> candles)Estrela da manhã terminando no último candle da lista.
static bool EveningStar(IReadOnlyList<Candle> candles, int i)Depois de alta: alta longa, corpo curto acima dela (com gap no corpo) e baixa fechando abaixo do meio da primeira. Vale também com doji no meio.
static bool EveningStar(IReadOnlyList<Candle> candles)Estrela da tarde terminando no último candle da lista.
static bool ThreeWhiteSoldiers(IReadOnlyList<Candle> candles, int i)Três candles de alta longos, com pouca sombra superior, cada um fechando acima do anterior e abrindo dentro do corpo do anterior.
static bool ThreeWhiteSoldiers(IReadOnlyList<Candle> candles)Três soldados brancos terminando no último candle da lista.
static bool ThreeBlackCrows(IReadOnlyList<Candle> candles, int i)Três candles de baixa longos, com pouca sombra inferior, cada um fechando abaixo do anterior e abrindo dentro do corpo do anterior.
static bool ThreeBlackCrows(IReadOnlyList<Candle> candles)Três corvos negros terminando no último candle da lista.

IFR (RSI)

Rsi

RSI (IFR) de Wilder, 0 a 100. A conta é a mesma do gráfico da HTS: o primeiro valor é NaN (só fixa o fechamento anterior) e, do segundo em diante, as médias de ganho e perda avançam pela suavização de Wilder partindo de zero. Converge ao longo dos primeiros candles em vez de esperar N candles, por isso o valor existe cedo e ainda "assenta".

private Rsi rsi = null!;public override void OnStart() { rsi = new Rsi(14); }public override void OnBarClose(){    rsi.Update(Current.Close);    // sobrevendido: compra; voltou a sobrecomprado: zera    if (Position.IsFlat && rsi.Value < 30) Buy(1);    else if (Position.IsLong && rsi.Value > 70) ClosePosition();}
MembroO que faz
Rsi(int period)Cria o RSI com period candles na suavização de Wilder.
int PeriodO período (em candles).
override double Update(double value)Recebe o próximo valor (normalmente o fechamento) e devolve o RSI novo, de 0 a 100 (NaN no primeiro candle).

Força da tendência (ADX)

Adx

ADX de Wilder com as linhas direcionais. Mesma conta do ADX do gráfico: o primeiro candle só fixa o anterior (NaN); no segundo, ATR e DMs são semeados com o próprio valor e o ADX parte de zero; daí em diante tudo avança por suavização de Wilder (α = 1/N). O ADX "assenta" ao longo dos primeiros candles em vez de esperar N candles. Value é o ADX; DiPlus e DiMinus são as direcionais (as do DMI, que usa a mesma semente).

private Adx adx = null!;public override void OnStart() { adx = new Adx(14); }public override void OnBarClose(){    adx.Update(Current);    // só opera com tendência forte (ADX acima de 25), a favor da direcional dominante    if (Position.IsFlat && adx.Value > 25)    {        if (adx.DiPlus > adx.DiMinus) Buy(1);        else Sell(1);    }}
MembroO que faz
Adx(int period = 14)Cria o ADX com period candles na suavização de Wilder (padrão 14).
int PeriodO período (em candles).
double DiPlusO +DI (força da alta), de 0 a 100.
double DiMinusO −DI (força da baixa), de 0 a 100.
double DiPlusAgo(int barsAgo)O +DI barsAgo candles atrás (0 = agora).
double DiMinusAgo(int barsAgo)O −DI barsAgo candles atrás (0 = agora).
Output DiPlusSeriesO +DI como série (para Crossed e os utilitários de série).
Output DiMinusSeriesO −DI como série (para Crossed e os utilitários de série).
double Update(Candle candle)Recebe o candle fechado e devolve o ADX novo, de 0 a 100 (NaN no primeiro candle); +DI e −DI são atualizados junto.

SAR parabólico

ParabolicSar

SAR parabólico de Wilder, com a conta do SAR parabólico no gráfico: semeia no primeiro candle assumindo alta (SAR na mínima, extremo na máxima); a cada candle avança pelo fator de aceleração, nunca entra na faixa dos dois candles anteriores e, quando é tocado, vira no extremo alcançado. Os primeiros valores são arbitrários por construção. Value é o SAR; IsUptrend diz o lado.

private ParabolicSar sar = null!;public override void OnStart() { sar = new ParabolicSar(0.02, 0.2); }public override void OnBarClose(){    sar.Update(Current);    Plot("SAR", sar.Value, PlotStyle.Points);    // virou o SAR: zera e entra no lado novo    if (sar.FlippedNow)    {        ClosePosition();        if (sar.IsUptrend) Buy(1); else Sell(1);    }}
MembroO que faz
ParabolicSar(double step = 0.02, double max = 0.2)Cria o SAR com o fator de aceleração começando em step, somando step a cada novo extremo e limitado a max.
double StepO passo do fator de aceleração (também o valor inicial).
double MaxO limite do fator de aceleração.
bool IsUptrendO SAR está abaixo do preço (tendência de alta).
int Direction+1 em alta, −1 em baixa.
bool FlippedNowO SAR virou de lado neste candle.
double Update(Candle candle)Recebe o candle fechado e devolve o SAR novo (NaN se máxima ou mínima não é número).

SuperTrend

SuperTrend

SuperTrend: banda de Multiplier·ATR em volta do meio do candle, travada do lado da tendência (só aperta; afrouxa só quando o fechamento a atravessa, e aí a tendência vira). Mesma conta do SuperTrend no gráfico: NaN enquanto o ATR aquece; começa assumindo alta. Value é a linha (o stop); Direction é +1 em alta e −1 em baixa.

private SuperTrend st = null!;public override void OnStart() { st = new SuperTrend(10, 3); }public override void OnBarClose(){    st.Update(Current);    Plot("SuperTrend", st.Value);    // virou para alta: compra; virou para baixa: zera a compra    if (st.FlippedNow && st.IsUptrend && Position.IsFlat) Buy(1);    else if (st.FlippedNow && !st.IsUptrend && Position.IsLong) ClosePosition();}
MembroO que faz
SuperTrend(int atrPeriod = 10, double multiplier = 3)Cria o SuperTrend com ATR de atrPeriod candles e bandas a multiplier ATRs do meio do candle.
int AtrPeriodO período do ATR, em candles.
double MultiplierQuantos ATRs separam as bandas do meio do candle.
bool IsUptrendTendência de alta: o fechamento não perdeu a banda de baixo, e a linha é essa banda.
int Direction+1 em alta, −1 em baixa.
bool FlippedNowA tendência virou neste candle.
double UpperBandA banda de cima (o stop quando em baixa), mesmo quando a linha está do outro lado.
double LowerBandA banda de baixo (o stop quando em alta).
double Update(Candle candle)Recebe o candle fechado e devolve a linha do SuperTrend nova (NaN enquanto o ATR aquece).

HiLo Activator

HiLo

HiLo Activator (Gann/Krausz): média das máximas e média das mínimas dos N candles ANTERIORES (sem o atual). Fechou acima da média das máximas: alta, e a linha é a média das mínimas; fechou abaixo da média das mínimas: baixa, e a linha é a média das máximas; entre as duas, vale o lado de antes. Mesma conta do HiLo no gráfico (no primeiro candle entre as médias, o lado mais perto). NaN nos N primeiros candles.

private HiLo hilo = null!;public override void OnStart() { hilo = new HiLo(3); }public override void OnBarClose(){    hilo.Update(Current);    Plot("HiLo", hilo.Value, PlotStyle.Step);    // o HiLo virou: zera e acompanha o lado novo    if (hilo.FlippedNow)    {        ClosePosition();        if (hilo.IsUptrend) Buy(1); else Sell(1);    }}
MembroO que faz
HiLo(int period = 3)Cria o HiLo com médias de period candles (padrão 3).
int PeriodO período (em candles).
bool IsUptrendLado comprado: o último fechamento fora das médias foi acima da média das máximas, e a linha é a média das mínimas.
int Direction+1 em alta, −1 em baixa.
bool FlippedNowO HiLo trocou de lado neste candle.
double HighsAverageA média das máximas dos N candles anteriores (a linha quando em baixa).
double LowsAverageA média das mínimas dos N candles anteriores (a linha quando em alta).
double Update(Candle candle)Recebe o candle fechado e devolve a linha do HiLo nova (NaN nos N primeiros candles).

Aroon

Aroon

Aroon: há quantos candles saiu a máxima (Up) e a mínima (Down) dos últimos N, em percentual (100 = agora, 0 = no começo da janela); Value é o oscilador (alta − baixa). Mesma conta do Aroon, Aroon Down e Aroon Oscillator no gráfico: em empate vale o candle mais recente. NaN até ter N candles.

private Aroon aroon = null!;public override void OnStart() { aroon = new Aroon(25); }public override void OnBarClose(){    aroon.Update(Current);    // Aroon Up cruzou o Down para cima: começo de alta    if (Position.IsFlat && Crossed.Above(aroon.UpSeries, aroon.DownSeries)) Buy(1);    else if (Position.IsLong && Crossed.Below(aroon.UpSeries, aroon.DownSeries)) ClosePosition();}
MembroO que faz
Aroon(int period = 25)Cria o Aroon com janela de period candles (padrão 25).
int PeriodO período (em candles).
double UpAroon Up.
double DownAroon Down.
double UpAgo(int barsAgo)O Aroon Up barsAgo candles atrás (0 = agora).
double DownAgo(int barsAgo)O Aroon Down barsAgo candles atrás (0 = agora).
Output UpSeriesO Aroon Up como série (para Crossed e os utilitários de série).
Output DownSeriesO Aroon Down como série (para Crossed e os utilitários de série).
double Update(Candle candle)Recebe o candle fechado e devolve o oscilador novo (Up − Down, de −100 a 100; NaN no aquecimento); Up e Down são atualizados junto.

Desvio padrão

StdDev

Desvio padrão POPULACIONAL dos últimos N valores (divide por N, como o gráfico da HTS e o ta.stdev do Pine). NaN até ter N valores e se algum não é número.

private StdDev desvio = null!;private Sma media = null!;public override void OnStart() { desvio = new StdDev(20); media = new Sma(20); }public override void OnBarClose(){    desvio.Update(Current.Close);    media.Update(Current.Close);    // filtro: mercado parado (desvio pequeno) não entra    if (desvio.IsReady && desvio.Value > 30 && Position.IsFlat && Crossed.Above(Closes, media)) Buy();}
MembroO que faz
StdDev(int period = 20)Cria o desvio padrão com period candles (1 a 500).
int PeriodO período (em candles).
override double Update(double value)Avança um candle com um valor (o fechamento, outro indicador...) e devolve o desvio padrão novo (NaN no aquecimento).

Volatilidade histórica

HistoricalVolatility

Volatilidade histórica: desvio padrão (populacional) dos últimos N log-retornos (ln(fechamento/anterior)), vezes a raiz de Annualization (252 pregões), em percentual. Mesma conta do volatilidade histórica no gráfico. O primeiro candle não tem retorno, então o primeiro valor sai no candle N + 1. Retorno com preço zero ou negativo é NaN e invalida a janela.

private HistoricalVolatility volatilidade = null!;public override void OnStart() { volatilidade = new HistoricalVolatility(20, 252); }public override void OnBarClose(){    volatilidade.Update(Current.Close);    Plot("Vol. histórica %", volatilidade.Value);    // avisa no log quando a volatilidade passa de 40% ao ano    if (volatilidade.IsReady && volatilidade.Value > 40) Log("Volatilidade acima de 40% ao ano");}
MembroO que faz
HistoricalVolatility(int period = 20, int annualization = 252)Cria a volatilidade histórica com period log-retornos, anualizada por annualization períodos por ano (252 pregões no diário).
int PeriodO período (em log-retornos, um por candle).
int AnnualizationQuantos períodos há num ano para anualizar (o desvio é multiplicado pela raiz deste número). Mínimo 1.
override double Update(double value)Avança um candle com um preço (normalmente o fechamento) e devolve a volatilidade nova, em % (NaN no aquecimento).

Saldo de volume (OBV)

Obv

OBV (Granville): soma o volume quando o fechamento sobe, subtrai quando cai, não mexe quando empata. Mesma conta do OBV no gráfico: começa em zero no primeiro candle (o nível não quer dizer nada, só a direção).

private Obv obv = null!;private Ema mediaDoObv = null!;public override void OnStart() { obv = new Obv(); mediaDoObv = new Ema(20); }public override void OnBarClose(){    obv.Update(Current);    mediaDoObv.Update(obv.Value);    // o volume confirma a alta: OBV cruza a própria média para cima    if (Position.IsFlat && Crossed.Above(obv, mediaDoObv)) Buy();}
MembroO que faz
double Update(Candle candle)Avança com o candle fechado (fechamento e volume) e devolve o OBV novo.

Acumulação e distribuição

AccumulationDistribution

Linha de acumulação/distribuição (Chaikin): acumula volume × posição do fechamento na faixa do candle (−1 a +1). Mesma conta do linha A/D no gráfico: candle com faixa zero não mexe na linha (repete o valor).

private AccumulationDistribution ad = null!;public override void OnStart() { ad = new AccumulationDistribution(); }public override void OnBarClose(){    ad.Update(Current);    Plot("A/D", ad.Value);    // divergência: preço caindo e a linha A/D subindo (acumulação)    if (Current.Close < Closes[5] && ad.Value > ad[5]) Log("Acumulação na queda");}
MembroO que faz
double Update(Candle candle)Avança com o candle fechado (máxima, mínima, fechamento e volume) e devolve a linha A/D nova (NaN até o primeiro candle com faixa).

Oscilador de Chaikin

ChaikinOscillator

Oscilador de Chaikin: EMA rápida − EMA lenta da linha de acumulação/distribuição (o MACD do fluxo). Mesma conta do Chaikin Oscillator no gráfico: valor desde o primeiro candle (zero), convergindo.

private ChaikinOscillator chaikin = null!;public override void OnStart() { chaikin = new ChaikinOscillator(3, 10); }public override void OnBarClose(){    chaikin.Update(Current);    // fluxo virou comprador: oscilador cruza o zero para cima    if (Position.IsFlat && Crossed.Above(chaikin, 0)) Buy();    else if (Position.IsLong && Crossed.Below(chaikin, 0)) ClosePosition();}
MembroO que faz
ChaikinOscillator(int fastPeriod = 3, int slowPeriod = 10)Cria o oscilador com a EMA rápida de fastPeriod candles e a lenta de slowPeriod candles.
int FastPeriodO período da EMA rápida (em candles).
int SlowPeriodO período da EMA lenta (em candles).
double Update(Candle candle)Avança com o candle fechado (máxima, mínima, fechamento e volume) e devolve o oscilador novo (NaN até o primeiro candle com faixa).

Índice de força

ForceIndex

Force Index (Elder): EMA de (fechamento − fechamento anterior) × volume. Mesma conta do Force Index no gráfico: NaN no primeiro candle; a EMA semeia com o primeiro produto.

private ForceIndex forca = null!;private Ema tendencia = null!;public override void OnStart() { forca = new ForceIndex(2); tendencia = new Ema(50); }public override void OnBarClose(){    forca.Update(Current);    tendencia.Update(Current.Close);    // Elder: tendência de alta e força negativa (correção) = ponto de compra    if (Position.IsFlat && Current.Close > tendencia.Value && forca.Value < 0) Buy();}
MembroO que faz
ForceIndex(int period = 13)Cria o Force Index com EMA de period candles (1 a 500).
int PeriodO período da EMA (em candles).
double Update(Candle candle)Avança com o candle fechado (fechamento e volume) e devolve o Force Index novo (NaN no primeiro candle).

Tendência preço-volume (PVT)

Pvt

PVT (Price Volume Trend): acumula volume × variação percentual do fechamento. Mesma conta do PVT no gráfico: NaN no primeiro candle (não há variação); depois parte de zero.

private Pvt pvt = null!;private Sma sinal = null!;public override void OnStart() { pvt = new Pvt(); sinal = new Sma(21); }public override void OnBarClose(){    pvt.Update(Current);    sinal.Update(pvt.Value);    Plot("PVT", pvt.Value);    Plot("Sinal", sinal.Value);    if (Position.IsLong && Crossed.Below(pvt, sinal)) ClosePosition();}
MembroO que faz
double Update(Candle candle)Avança com o candle fechado (fechamento e volume) e devolve o PVT novo (NaN no primeiro candle).

Ondas de Weis

WeisWave

Weis Wave: o volume acumulado da onda atual. Não existe no gráfico da HTS; a regra aqui é a clássica de David Weis sem filtro de tamanho: a onda de alta segue enquanto o fechamento não cai abaixo do maior fechamento da onda (menos Reversal pontos, quando informado); quando cai, começa uma onda de baixa naquele candle, com o volume dele, e vice-versa. Fechamento igual continua a onda. A primeira onda tem o lado do primeiro candle (de alta se fechou acima de onde abriu, senão de baixa). Value é o volume da onda com sinal (positivo na alta, negativo na baixa); WaveVolume é o módulo; PreviousWave é o volume (com sinal) da onda que acabou.

private WeisWave ondas = null!;public override void OnStart() { ondas = new WeisWave(50); }public override void OnBarClose(){    ondas.Update(Current);    Plot("Onda", ondas.Value, PlotStyle.Histogram);    // começou uma onda de alta: mostra quanto volume teve a onda de baixa que acabou    if (ondas.FlippedNow && ondas.IsUptrend) Log($"Nova onda de alta; a de baixa somou {Math.Abs(ondas.PreviousWave)} contratos");}
MembroO que faz
WeisWave(double reversal = 0)Cria o Weis Wave; a onda só vira quando o fechamento recua mais que reversal pontos do extremo (0 = qualquer recuo).
double ReversalQuanto o fechamento precisa andar contra o extremo da onda para virar (0 = qualquer recuo).
bool IsUptrendA onda atual é de alta.
int DirectionO lado da onda atual: +1 na alta, −1 na baixa.
bool FlippedNowUma onda nova começou neste candle.
double WaveVolumeO volume da onda atual, sem sinal.
double PreviousWaveO volume (com sinal) da onda que acabou de terminar; NaN antes da primeira virada.
int BarsInWaveCandles na onda atual (contando o atual).
double WaveExtremeO fechamento extremo da onda atual (o maior na alta, o menor na baixa).
double Update(Candle candle)Avança com o candle fechado (abertura, fechamento e volume) e devolve o volume da onda com sinal.

VWAP

Vwap

VWAP por período: Σ(preço·volume)/Σ(volume) acumulado desde o início do dia, da semana ou do mês, zerando na virada (pela Date em Brasília e PeriodKey). A conta é a do VWAP do gráfico: o preço é o FECHAMENTO do candle (não o preço típico), e o valor existe desde o primeiro candle do período. Com typicalPrice: true a conta usa (máxima + mínima + fechamento)/3, como outras plataformas. Volume zero no período inteiro dá NaN.

private Vwap vwap = null!;public override void OnStart() { vwap = new Vwap(Period.Day); }public override void OnBarClose(){    vwap.Update(Current);    Plot("VWAP", vwap.Value);    // compra quando o preço retoma o VWAP do dia    if (Position.IsFlat && Crossed.Above(Closes, vwap)) Buy();}
MembroO que faz
Vwap(Period period = Period.Day, bool typicalPrice = false)Cria o VWAP que zera a cada period (dia, semana ou mês); com typicalPrice a conta usa o preço típico em vez do fechamento.
Period PeriodDe quanto em quanto tempo o VWAP zera (dia, semana ou mês).
bool TypicalPriceA conta usa o preço típico, (máxima + mínima + fechamento)/3, em vez do fechamento.
double Update(Candle candle)Avança com o candle fechado (preço e volume) e devolve o VWAP novo; zera na virada do período.

VWAP ancorado

AnchoredVwap

VWAP ancorado: acumula desde o candle em que o robô chamou Anchor (um rompimento, a abertura de um evento, um topo). Antes da primeira âncora o valor é NaN. Chame Anchor() ANTES de Update(Current) no mesmo candle para que o candle da âncora entre na conta.

private Highest maxima = null!;private AnchoredVwap vwap = null!;public override void OnStart() { maxima = new Highest(20); vwap = new AnchoredVwap(); }public override void OnBarClose(){    maxima.Update(Current);    // ancora o VWAP no candle que rompeu a máxima dos 20 anteriores (antes do Update)    if (Current.Close > maxima[1]) vwap.Anchor();    vwap.Update(Current);    if (vwap.IsReady) Plot("VWAP ancorado", vwap.Value);}
MembroO que faz
AnchoredVwap(bool typicalPrice = false)Cria o VWAP ancorado, ainda sem âncora; com typicalPrice a conta usa o preço típico em vez do fechamento.
bool TypicalPriceA conta usa o preço típico, (máxima + mínima + fechamento)/3, em vez do fechamento.
bool IsAnchoredHá uma âncora (o indicador está acumulando).
int BarsSinceAnchorCandles acumulados desde a âncora (0 sem âncora).
void Anchor()Zera a acumulação: o próximo Update começa um VWAP novo.
double Update(Candle candle)Avança com o candle fechado (preço e volume) e devolve o VWAP desde a âncora (NaN antes da primeira âncora).