Códigos de exemplo? Tome Snippets! Outros Snippets Estimated reading: 11 minutes 3049 views Introdução Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores. Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu. Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria). Snippets Escrevendo no Console com Timestamp para facilitar Debug A partir da versão beta 215, tornou-se possível no Backtesting escrever texto no Console, o que facilita a depuração de estratégias. Segue abaixo um snippet no qual há uma função que retorna o timestamp da barra. O corpo principal da estratégia apenas gera na aba “Compilação” o log com mensagem “Teste” precedido do timestamp no formato “DD/MM/AAAA HH:MM”. var horario: integer; timestamp : string; //--------------------------------------------------- function getTimestamp: string; var dia, mes_ano, hora: string; begin if Month(Date) < 10 then mes_ano := "0" + Month(Date) + "/" + Year(Date) else mes_ano := Month(Date) + "/" + Year(Date); if DayofMonth(Date) < 10 then dia := "0" + DayofMonth(Date) + "/" + mes_ano else dia := DayofMonth(Date) + "/" + mes_ano; if Floor(Time/100) < 10 then hora := "0" + Floor(Time/100) else hora := Floor(Time/100); if Mod(Time,100) < 10 then hora := hora + ":" + "0" + Mod(Time,100) else hora := hora + ":" + Mod(Time,100); Result := dia + " " + hora + " - "; end; //--------------------------------------------------- begin if horario <> Time then begin timestamp := getTimestamp; ConsoleLog(getTimestamp() + "Teste", clBlue); horario := Time; end; end; Arrendondamento de valores para N casas decimais Como o Profit não tem nativamente uma função para arrendondar um float para uma determinada quantidade de casas decimais (N), a função abaixo foi implementada com esta finalidade. var fValorOriginal: float; fValorArred: float; function NTB_ArredondarFloat(Value: float; nCasas: integer):float; var fValor: float; fParteInteira: float; fParteDecimal: float; begin fValor := Value; fParteInteira := IntPortion(fValor); fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas)); Result := fParteInteira + fParteDecimal/Power(10,nCasas); end; begin fValorOriginal := 12.345819; fValorArred := NTB_ArredondarFloat(fValorOriginal,2); if LastBarOnChart then PlotText(fValorArred,clWhite, - 1,8); end; Restrição de estratégia pelo código do ativo O código abaixo visa identificar o código do ativo no qual a estratégia ou robô está sendo aplicado. A estratégia apenas é executada se o ticker do ativo for igual a constante “cAtivoEstrategia”.Isto evita que as estratégias sejam rodadas de forma equivocada em ativos para os quais os parâmetros da estratégia não foram otimizados. const cAtivoEstrategia = "PETR4"; begin if GetAsset = cAtivoEstrategia then begin //TODO CÓDIGO FONTE DA SUA ESTRATÉGIA DEVE ESTAR AQUI DENTRO PaintBar(clGreen); end else if LastBarOnChart then plotText("Usar em " + cAtivoEstrategia,clWhite,-1,12); end Restrição de estratégia pelo tipo/frequência do gráfico O código abaixo visa identificar o tipo de gráfico no qual a estratégia ou robô está sendo aplicado. Caso não corresponda ao tipo de gráfico para o qual a estratégia foi otimizada, é exibida mensagem com informação sobre o tipo de gráfico adequado.Isto evita que as estratégias sejam rodadas de forma equivocada para tipos de gráficos e frequências temporais diferentes daquelas para as quais foi validada. var bStarted, bGraficoOK: boolean; iTipoGrafico: integer; strMensagemErro: string; begin if Not bStarted then begin bStarted := true; iTipoGrafico := GraphicInterval; //Verificação de Renko 3R if (iTipoGrafico = itRenko) and (GraphicOffset = 3) then bGraficoOK := true else strMensagemErro := "Estratégia para 3R"; //Verificação de Gráfico de 5 minutos //if (iTipoGrafico = itMinute) and (GraphicOffset = 5) then bGraficoOK := true //else strMensagemErro := "Estratégia para 5 Minutos"; end; // Robô/Estratégia só irá ser executada se o gráfico estiver configurado // adequadamente if bGraficoOK then begin end // Se gráfico não estiver na configuração adequada, pinta todas as barras de vermelho // e exibe texto na última barra else begin paintBar(clRed); if LastBarOnChart then plotText(strMensagemErro,clWhite,-1,9); end; end Ignorar boxes de Gap em gráficos de Renko É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Quando se está em um gráfico de Renko, o código da estratégia é processado para cada box incluído no gráfico devido ao gap.Este código apresenta uma forma simples de não executar lógica sobre boxes referentes à gap. Os boxes de gap possuem duração igual a zero. Para realizar a verificação da duração temporal em minutos de um box, basta utilizar o comando BarDurationF. var bLocalizouBoxesGap : boolean; iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer; begin // Código é aplicável apenas à gráficos do tipo Renko if GraphicInterval = itRenko then begin // Identificação de Box relacionados a GAP if Date <> iDataUltimoBox then begin iUltimoBoxDiaAnterior := CurrentBar - 1; iBoxDeGAP := CurrentBar; bLocalizouBoxesGap := false; end; iDataUltimoBox := Date; if Not bLocalizouBoxesGap then if BarDurationF = 0 then begin iBoxDeGAP := CurrentBar; PaintBar(clRed); end else begin //Aqui foi identificado o primeiro box que não é de GAP bLocalizouBoxesGAP := true; end; //Aqui executa a estratégia em boxes que não são devido à //gap de abertura if bLocalizouBoxesGAP then begin PaintBar(clGreen); end; end // O Gráfico não é do tipo Renko! else if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10); end Cálculo de Gap em gráficos de Renko em termos de boxes É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Este código visa calcular o tamanho do gap nos gráficos de Renko em termos da quantidade de boxes.OBS: É importante ressaltar que devido à própria natureza do gráfico de Renko, o cálculo de gap não é preciso quanto o cálculo de gap pelo gráfico de Candle.OBS2: Os comandos OpenD(0) e CloseD(1) também podem ser utilizados em gráficos de renko, reduzindo o código abaixo a gap := (OpenD(0) – CloseD(1))/((GraphicOffset-1)*MinPriceIncrement). No entanto, os valores encontrados divergem em alguns dias de gap por 1 box. Pela minha apuração, o código abaixo apresenta os resultados corretos. var bLocalizouBoxesGap : boolean; fTamanhoBox : float; iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer; fGAPdoDiaBox, fAberturaBox, fFechamentoDiaAnteriorBox: float; begin // Código é aplicável apenas à gráficos do tipo Renko if GraphicInterval = itRenko then begin fTamanhoBox := (GraphicOffset-1)*MinPriceIncrement; // Identificação de Box relacionados a GAP if Date <> iDataUltimoBox then begin iUltimoBoxDiaAnterior := CurrentBar - 1; iBoxDeGAP := CurrentBar; bLocalizouBoxesGap := false; end; iDataUltimoBox := Date; if Not bLocalizouBoxesGap then if BarDurationF = 0 then iBoxDeGAP := CurrentBar else begin //Aqui foi identificado o primeiro box que não é de GAP bLocalizouBoxesGAP := true; //Coloque abaixo o que deseja fazer no primero box do dia que não é GAP // -------------------------------------------------------------------- if (Open < Close[1]) Or (Open > Close[1]) then fAberturaBox := Open[1] else fAberturaBox := Close[1]; fFechamentoDiaAnteriorBox := Close[CurrentBar - iUltimoBoxDiaAnterior]; fGAPdoDiaBox := (fAberturaBox - fFechamentoDiaAnteriorBox)/fTamanhoBox; if fGAPdoDiaBox <> 0 then begin if fGAPdoDiaBox > 0 then PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clGreen,-1,9) else PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clRed,-1,9); PaintBar(clRed); end; // -------------------------------------------------------------------- end; end // O Gráfico não é do tipo Renko! else if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10); end Execução de estratégia em frequência superamostrada É de conhecimento de quem opera gráficos com tempo gráfico maior os impactos de se executar ordens apenas no fechamento dos candles/boxes.Este Snippet visa tornar as ordens mais tempestivas, exemplificando uma forma de executar uma estratégia/robô em um tempo gráfico menor do que o original. Naturalmente que isso exige um código fonte mais complexo para tratar de forma adequada os cálculos de indicadores utilizados na estratégia.O código de exemplo abaixo, demonstra como utilizar uma média móvel em um tempo gráfico superamostrado equivalente ao tempo gráfico original da estratégia (e com valor superior). Bem como também demonstra como seria o cálculo para obter a média de fechamento em tempos gráficos superiores ao gráfico supermostrado.OBS: Embora não seja um requisito, sugere-se que o tempo gráfico original seja um múltiplo do tempo gráfico superamostrado. //LIMITAÇÃO IMPORTANTE: Não dá para fazer em escala de segundos //devido a função time não retornar segundos const // Estratégia originalmente rodava em gráfico de 15 min cTempoGraficoOriginal = 15; //Qtde de periodos no tempo gráfico original cQtdePeriodosMedia = 20; //Horario inicial de negociação do ativo //0900 para futuros, 1000 para mercado a vista cHoraInicioNegociacao = 0900; var bStarted: boolean; iTempoGraficoAtual: integer; iQtdePeriodosEquivalente: integer; fMediaSuperAmostradaEquivalente: float; fInicializacaoMedia: float; fMediaTempoGraficoOriginal: float; iQtdePeriodosCalculados: integer; iHorarioEmMinutos: integer; iHorarioGrafSuperior: integer; bCalculouTempoGrafSuperior: boolean; begin //1a opção: Dar preferencia sempre que possível // Identifica tempo gráfico utilizado e qtde de periodos equivalente para média superamostrada iTempoGraficoAtual := GraphicOffset; iQtdePeriodosEquivalente := Floor(cTempoGraficoOriginal/iTempoGraficoAtual)*cQtdePeriodosMedia; // Obtem média superamostrada equivalente fMediaSuperAmostradaEquivalente := Media(iQtdePeriodosEquivalente,Close); //Plot da série para inspeção PlotN(1,fMediaSuperAmostradaEquivalente); SetPlotColor(1, clWhite); SetPlotWidth(1,2); SetPlotStyle(1, psDash); //2a opção: Exige mais linhas de código para gerenciar execução //Amostrando apenas os valores de fechamento do Tempo gráfico original iHorarioEmMinutos := Floor(Time/100)*60+Mod(Time,100) - (Floor(cHoraInicioNegociacao/100)*60+Mod(cHoraInicioNegociacao,100)); if Not bStarted then begin iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)); bStarted := true; end; // Bloco para criar mecanismo de calcular apenas uma vez para o gráfico superior if (CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)) <> iHorarioGrafSuperior) then begin iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)); bCalculouTempoGrafSuperior := false; end; // Cálculo da média no tempo gráfico original if (Mod(iHorarioEmMinutos, cTempoGraficoOriginal) = 0) and Not bCalculouTempoGrafSuperior then begin bCalculouTempoGrafSuperior := true; if (iQtdePeriodosCalculados < cQtdePeriodosMedia) then begin iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1; fInicializacaoMedia := fInicializacaoMedia + Close[1]; end else if (iQtdePeriodosCalculados = cQtdePeriodosMedia) then begin fMediaTempoGraficoOriginal := fInicializacaoMedia/iQtdePeriodosCalculados; iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1; end else fMediaTempoGraficoOriginal := (fMediaTempoGraficoOriginal*cQtdePeriodosMedia - Close[1+cQtdePeriodosMedia*Floor(cTempoGraficoOriginal/iTempoGraficoAtual)] + Close[1])/cQtdePeriodosMedia; end; //Plot da série para inspeção PlotN(2,fMediaTempoGraficoOriginal); SetPlotColor(2, clRed); SetPlotWidth(2,2); SetPlotStyle(2, psSolid); end Como utilizar dados de preço de outros ativos O código abaixo apenas exemplifica como obter os dados OHLCV de outras ativos em uma estratégia, o que pode ser feito via parâmetro ou constante. Caso o ativo desejado seja uma ação, deve-se atentar para modificar o feedBMF para feedBovespa. const cAtivo1 = Asset("INDFUT",feedBMF); input pAtivo2("WINFUT",feedBMF); pQtdePeriodos(50); var fMediaAtivo1, fMediaAtivo2: float; begin fMediaAtivo1 := Media(pQtdePeriodos,cAtivo1.Close); fMediaAtivo2 := Media(Floor(pQtdePeriodos*1/3),pAtivo2.Close); plot(fMediaAtivo1); plot2(fMediaAtivo2); end;