Aula 05 – Hands-on: Primeiros programas em Pascal
Nesta última aula iremos implementar dois programas de exemplo para consolidar o que vimos no curso básico e preparar o caminho para começarmos a implementação de estratégias automatizadas.
1. Por onde "começar"?
Se você assistiu/leu as aulas do curso básico até aqui, deve estar se perguntando: por qual linguagem de programação devo “começar” a estudar e implementar meus primeiros programas/estratégias?
Eu penso que para aprender uma linguagem de programação, é necessário atender a um propósito, a uma finalidade prática, para não corrermos o risco de perder a motivação no meio do caminho. Como nesta comunidade nosso objetivo é compartilhar conhecimento e experiências sobre automatização de estratégias para negociação de ativos, iremos selecionar uma linguagem que facilite alcançar esse objetivo.
Neste contexto, existem duas plataformas com maior capilaridade no mercado: Profit Chart (Empresa Nelogica) e MetaTrader (Empresa MetaQuotes Software), quando se trata de negociação de ativos na B3. Ainda tem outras plataformas disponíveis por aí como TradingView e outras que também podem atuar na B3 quanto em criptoativos.
O Profit Chart baseia-se na linguagem Pascal, enquanto o MetaTrader baseia-se na linguagem C.
Iremos iniciar a construção das bases de conhecimento desta comunidade abordando inicialmente implementações de estratégias no Profit Chart. Por que? Porque eu acredito que seja uma plataforma mais amigável para quem está iniciando e com uma curva de aprendizado menor. Está certo que a plataforma é mais limitada em termos de implementação de estratégias do que o MetaTrader. Mas para quem está iniciando, ainda há muito espaço para aprender, testar seu conhecimento e implementar diversas estratégias.
O caminho natural em um segundo momento será abordarmos também a programação em C visando utilização do MetaTrader, software que apresenta uma interface gráfica menos amigável e uma curva de aprendizado maior, embora tenha uma comunidade mundial ativa desenvolvendo soluções.
Assim, visando reduzir nosso nível de preocupação com o que é essencial utilizaremos para esta aula um console virtual e compilador hospedado na web. Faremos isso para evitar passarmos pelo processo de baixar na internet um compilador de Pascal, instalarmos uma API para programar (nada mais é que um editor de texto específico para escrever código fonte). Pois este processo não será necessário para programar as estratégias no Profit Chart, não agregando informação relevante nesse momento.
Então clique em uma das opções de compiladores online abaixo para abrir em uma nova aba o console e compilador online de Pascal para prosseguirmos com esta aula!
Em todos os compiladores onlines haverá uma seção na página onde você poderá editar o código-fonte, e outra seção que será o terminal de comando no qual você irá visualizar o resultado da execução do seu programa. Cada compilador tem um botão para executar o código que pode estar sinalizado como “Run”, “Run code”, “Execute”, etc…
2. Entendendo a estrutura básica de um programa em Pascal
Ao abrir qualquer um dos links acima, você verá no editor de código fonte, possivelmente, o famoso programa “HelloWorld” que qualquer curso de programação irá ensinar como primeira lição! Vamos entender o que está escrito!?
Program HelloWorld(output);
begin
writeln('Hello, world!');
end.
Em Pascal todo programa começa com a declaração do nome do programa: Program HelloWorld. Em parentêses são fornecidos os parâmetros do programa. O parâmetro output é uma variável especial que se refere ao terminal de comando, e que especifica que neste programa os comandos de escrita (writeln, abreviação de write line) serão direcionados para o terminal (tela à direita do compilador virtual).
Entre as linhas 2 e 4 está o corpo do programa HelloWorld, que deve estar entre as palavras reservadas begin e end. (não esqueça do ponto!).
Este é um programa muito simples! A única coisa que ele faz é escrever em tela a string (sequencia de caracteres) “Hello, world!”.
Clique no botão “Execute” no compilador virtual. Observe que o código do programa Hello World será compilado, e caso não haja nenhum erro de compilação, será executado! Nas últimas linhas do lado direito da tela, você deve visualizar o seguinte resultado, demonstrando que seu código foi compilado e o resultado da execução.
Parabéns! Você acabou de compilar e executar seu primeiro programa na linguagem Pascal! Agora vamos explorar um pouco mais os conceitos que você aprendeu até o momento, implementando alguns programas em Pascal.
3. Hello, market! Uma versão um pouco mais elaborada...
Entre as linhas 1 e 2 do código fonte que vimos anteriormente, o Pascal nos permite realizar algumas coisas:
- Declarar bibliotecas que serão utilizadas pelo programa (comando uses);
- Declarar constantes (comando const);
- Declarar variáveis globais (comando var);
- Declarar functions/procedures.
As bibliotecas (library) são um repositório de funções e tipos de dados que permitem facilitar escrever um programa para determinada finalidade. Por exemplo, a biblioteca strings possui algumas funcionalidades para facilitar a manipulação de dados de texto. Toda biblioteca possui uma documentação com descrição de como utilizar os tipos de dados e funções.
As constantes são definições de dados que não podem ter seu valor alterado dentro do programa.
As variáveis globais são variáveis que podem ser utilizadas em qualquer lugar de seu programa principal e, naturalmente, podem ter seu valor modificado durante a execução do programa.
As funções (functions) são pedaços reutilizáveis de código fonte que retornam algum valor, enquanto os procedimentos (procedures) não retornam nenhum valor.
A seguir vamos complicar o código fonte de forma incremental para explorarmos a linguagem Pascal.
3.1 Declarando constantes
Vamos mudar o nome do programa para “HelloMarket” e declarar uma constante chamada “dizerHello” do tipo boolean e que tenha o valor verdadeiro. Vamos escrever “Hello, market” apenas se “dizerHello” for verdadeira. Veja abaixo como fica o código fonte:
Program HelloMarket(output);
const
dizerHello = true;
begin
if dizerHello = true then
writeln('Hello, market!');
end.
Vamos nos atentar para alguns detalhes:
- A atribuição de valor às constantes na seção const se dá utilizando o sinal “=”;
- O operador de igualdade para condição do if também utiliza o sinal “=”, mas não trata de uma atribuição de valor e sim de uma expressão booleana;
- Quando há apenas um comando a ser executado dentro de um controle de decisão/repetição, não há necessidade de utilizar os delimitadores begin…end;
Ao executar o código acima, você irá verificar que o resultado é o mesmo. Você pode tentar mudar a atribuição da constante “dizerHello” para false e verificar o resultado do programa.
3.2 Utilizando biblioteca sysutils
Vamos utilizar a biblioteca sysutils que possui várias funções interessantes para ajudar a escrever programas em Pascal. Como todo programador, você terá que se acostumar a ler a documentação das bibliotecas para aprender a utilizar as funções e até mesmo ver exemplos de uso. A documentação da biblioteca sysutils pode ser acessada aqui.
Agora vamos declarar uma variável do tipo string, chamada “frase”, contendo o texto que iremos imprimir na tela, na seção var do nosso programa. Também vamos usar a função Concat para concatenar (unir) duas strings: “Hello, ” e “market!”. Em seguida vamos usar a função UpperCase para transformar o resultado da concatenção em letras maiuscúlas e armazenar na variável “frase”. Vamos lá!?
Program HelloMarket(output);
uses sysutils;
const
dizerHello = true;
var
frase : string;
begin
frase := UpperCase(Concat('Hello, ', 'market!'));
if dizerHello = true then
writeln(frase);
end.
Você observará que o resultado do programa ainda será o mesmo, exceto que as letras estarão em maiúsculo.
3.3 Imprimindo "Hello, market!" n vezes
Bom, agora vamos utilizar um controle de repetição para imprimir o texto “Hello, market!” quantas vezes desejarmos.
Para isso vamos utilizar o controle for e também precisaremos declarar duas variáveis auxiliares do tipo inteiro, uma para fazer a contagem (variável i) e outra para dizer quantas vezes devemos repetir o texto (n_vezes). Veja como seria o código abaixo.
Program HelloMarket(output);
uses sysutils;
const
dizerHello = true;
var
frase : string;
i, n_vezes : integer;
begin
n_vezes := 5;
frase := UpperCase(Concat('Hello, ', 'market!'));
if dizerHello = true then
for i := 1 to n_vezes do
writeln(i, ') ', frase);
end.
O resultado esperado da execução do programa segue abaixo:
3.4 Criando uma procedure
Vamos agora implementar uma procedure que recebe como parâmetro uma string e uma quantidade. Esses parâmetros servirão para dizer o texto que deve ser impresso e quantas vezes isso deve ocorrer.
Iremos implementar uma procedure porque em Pascal é esse nome que se dá a uma “função” que não retorna nenhum resultado para o programa principal. Veja abaixo como implementamos! O resultado esperado deve ser exatamente o mesmo da seção anterior.
Program HelloMarket(output);
uses sysutils;
const
dizerHello = true;
var
frase : string;
i, n_vezes : integer;
procedure printHello(texto: string; t: integer);
begin
for i:=1 to t do
writeln(i, ') ', frase);
end;
begin
n_vezes := 5;
frase := UpperCase(Concat('Hello, ', 'market!'));
if dizerHello = true then
printHello(frase, n_vezes);
end.
Note que no corpo principal do programa, existem duas variáveis chamadas n_vezes e frase, as quais são passadas como parâmetro para a procedure printHello. Dentro dessa procedure, os parâmetros podem possuir nomes diferentes, que é exatamente o caso. Dentro de printHello, a variável frase é chamada texto e a variável n_vezes é chamada de t. Qualquer alteração nos valores das variáveis texto e t não refletirão mudança no valor das variáveis frase e n_vezes. Isto deve-se ao fato dos parâmetros serem passados para as funções/procedures como valores.
Caso o programador deseja-se modificar os valores das variáveis fornecidas como parâmetros no escopo que chamou a função, ou seja, passando a referência das variáveis originais, bastaria definir os parâmetros precedidos com o comando var.
Esses mecanismos de passagem de parâmetros como valor ou como referência para funções ocorre em todas as linguagens de programação.
3.5 Obtendo dados do usuário
Obter dados externos é uma tarefa muito comum em programação. Ora o programa pode receber dados via terminal de comando, quando o dado a ser inserido é relativamente simples, ora o programa pode receber dados via arquivo de texto com um padrão definido, quando o volume e complexidade dos dados a serem recebidos justificar.
A última parte desse primeiro exercício de programação, será obtermos do usuário a quantidade de vezes que a frase “Hello, market!” deve ser impressa. Desta forma, vamos programar para que o programa peça esta informação e atue com este dado. Vamos lá!? Veja o código abaixo:
Program HelloMarket(output);
uses strings;
const
hello = 'Hello, market!';
var
i, vezes: integer;
dizerHello: boolean;
procedure printHello(print: boolean; t: integer);
begin
for i:=1 to t do
if (print = true) then
writeln(i, ' - ', hello);
end;
begin
dizerHello := true;
writeln('Digite a quantidade de vezes que deseja dizer ''Hello, market!'':');
readln(vezes);
printHello(dizerHello, vezes);
end.
O resultado da execução do programa, inserindo o número 7 (seguido de ENTER) segue abaixo:
4. Implementando Bubble Sort
Este segundo exercício de programação consistirá em entendermos um algoritmo e implementarmos um programa que o execute.
Utilizaremos um algoritmo clássico de ordenação, chamado Bubble sort. Já aviso que não é o algoritmo mais eficiente para realizar tal tarefa, mas foi um dos primeiros desenvolvidos e tem o seu valor didático. Se você se interessar em conhecer algoritmos de ordenação, veja esse vídeo aqui (Bubble sort está no minuto 4:00)!
Veja abaixo o algoritmo Bubble sort (fonte: wikipedia). Tente entender o algoritmo antes de passarmos para implementação.
procedure bubbleSort(A : list of sortable items)
n := length(A)
repeat
newn := 0
for i := 1 to n - 1 inclusive do
if A[i - 1] > A[i] then
swap(A[i - 1], A[i])
newn := i
end if
end for
n := newn
until n ≤ 1
end procedure
Vou tentar lhe dar uma ideia de como funciona o algoritmo Bubble sort. Pense em uma lista “A” de números inteiros aleatórios. O algoritmo irá começar comparando os dois primeiros elementos da lista, A[0] e A[1]. Se A[0] for maior que A[1], esses elementos serão trocados na lista, de tal forma que A[1] ficará na segunda posição e A[0] na primeira posição da lista. Em seguida, o algoritmo compara A[1] com A[2], e troca de posição se A[1] for maior que A[2]. Esse processo irá se repetir até chegar na comparação de A[n-i] e A[n], sendo n a quantidade de elementos da lista.
Perceba que ao iterar de 1 até n, o maior elemento da lista estará ao final desse controle (linhas 5 a 10 do algoritmo) na posição n-1. Mas o restante da lista ainda não está ordenada!
Portanto, repete-se a iteração na lista de 1 até n-1 (linhas 5 a 10), fazendo com que o segundo maior elemento da lista agora ocupe a posição n-2. Essas iterações vão ocorrer sucessivamente, até que a última iteração será apenas para comparar o elemento da primeira posição com o elemento da segunda posição. Essas repetições são controlados pelo comando repeat (linha 3) e sua condição de parada na linha 12.
O nome Bubble sort vem da analogia de um copo com refrigerante, as bolhas vão subindo, asssim como os maiores elementos também vão subindo de posição dentro da lista.
Veja abaixo a implementação do algoritmo e tente entender um pouco cada parte antes de prosseguirmos.
program programaOrdenacao;
uses SysUtils;
type
IntegerArray = array of Integer;
var
listaNaoOrdenada: IntegerArray;
listaOrdenada: IntegerArray;
i, tamanhoLista: integer;
procedure swap( var a, b:integer);
var
temp : integer;
begin
temp := a;
a := b;
b := temp;
end;
function BubbleSort(a: IntegerArray): IntegerArray;
var
n, newn, i:integer;
begin
n := high( a );
repeat
newn := 0;
for i := 1 to n do
begin
if a[ i - 1 ] > a[ i ] then
begin
swap( a[ i - 1 ], a[ i ]);
newn := i ;
end;
end ;
n := newn;
until n = 0;
BubbleSort := a;
end;
begin
Write('Insira o tamanho da lista que deseja ordenar (pressione ENTER):');
readln(tamanhoLista);
SetLength(listaNaoOrdenada, tamanhoLista);
SetLength(listaOrdenada, tamanhoLista);
writeln('Digite ', tamanhoLista, ' números inteiros separados ENTER:');
for i:= 0 to tamanhoLista-1 do
readln(listaNaoOrdenada[i]);
writeln();
Write('Lista inserida: ');
for i:= 0 to tamanhoLista-1 do
Write(listaNaoOrdenada[i], ' ');
Write(sLineBreak);
listaOrdenada := BubbleSort(listaNaoOrdenada);
Write('Lista ordenada: ');
for i:= 0 to tamanhoLista-1 do
Write(listaOrdenada[i], ' ');
Write(sLineBreak);
end.
Perceba que a implementação de um algoritmo simples já começa a apresentar detalhes particulares de implementação. Vamos explorar um pouco o código fonte para explicá-lo.
As linhas 1 e 2 são bem objetivas, nomeia o programa como “programaOrdenacao” e informa que será utilizada a biblioteca SysUtils. A documentação do compilador FreePascal que é utilizado nos links dos compiladores online, bem como a documentação das bibliotecas está disponível no site freepascal.org.
Nas linhas 4 e 5, a gente irá declarar um tipo de dado chamado IntegerArray que será um array de Integer (vimos o que era array na segunda aula!). Essa declaração de tipo é uma exigência da linguagem para utilizarmos este tipo de dados como retorno da função BubbleSort.
Entre as linhas 6 e 9, vamos declarar as variáveis que o programa irá utilizar: uma lista não ordenada que será informada pelo usuário, uma lista ordenada que será o resultado da função BubbleSort, uma variável de iteração i e o tamanho da lista a ser informada pelo usuário.
A procedure swap (entre as linhas 11 e 18) realiza apenas a troca de valores entre dois elementos. Essa procedure foi criada devido à recorrência desse tipo de operação no algoritmo BubbleSort. Note que os parâmetros foram passados como referência, o que permite, portanto, a manipulação de seus valores e reflexo no escopo que chamou a procedure swap, no caso, a função BubbleSort.
Entre as linhas 20 e 39, você verá a função BubbleSort que implementa o algoritmo visto anteriormente A função recebe como parâmetro um array de inteiros por valor, e retorna outro array de inteiros ordenado.
Entre as linhas 41 e 64 está o corpo principal do programa. O programa começa solicitando ao usuário o tamanho da lista que será ordenada. Assim, o usuário deve fornecer um número inteiro positivo ao programa.
Com base nessa informação, as linhas 45 e 46 definem o tamanho dos arrays listaNaoOrdenada e listaOrdenada. Em seguida, nas linhas 48 a 50, o programa pede que o usuário insira cada um dos números da lista de tamanho que ele definiu. Ao tempo que os valores são informados, eles são gravados nas posições do array listaNaoOrdenada (linha 49 e 50).
Entre as linhas 52 e 56, o programa irá imprimir na tela qual foi a lista de valores inseridas pelo usuário.
Na linha 58, é executada a chamada da função BubbleSort e o resultado é armazenado na variável listaOrdenada.
Por fim, a lista ordenada é impressa em tela (linha 60 a 63).
Talvez você cometa o erro de inserir uma letra quando o programa solicitar o tamanho da lista. Você observará que ocorrerá um erro no programa, pois o valor inserido pelo usuário seria do tipo string e o programa está tentando armazenar em uma variável do tipo inteiro.
Esses erros em programação são conhecidos como erros de execução e ocorrem sempre que o usuário realiza uma ação diferente do esperado. Em programação, o programador sempre tenta prever estes casos de “exceção” parar que o programa trate de forma correta. Por exemplo, o programa poderia informar que o valor inserido não é um número inteiro e solicitar novamente a inserção da informação até que ela venha correta. Assim, não haveria erro de execução e o programa continuaria sua execução até o fim. Situação análoga poderia ocorrer no momento de informar os elementos da lista.
Próximos passos
Bom, chegamos ao fim do curso básico de lógica de programação e espero que tenham conseguido entender os principais conceitos e ideias por trás da programação.
Esta última aula, na qual entramos em detalhes específicos da linguagem Pascal demonstra um pouco como é a vida de um programador…Especializar-se em uma linguagem específica leva tempo, exige horas de leitura de documentação, inúmeras pesquisas no google sobre erros de compilação, exemplos de código fonte, etc. É um trabalho de pesquisa e estudo que exige proativdade para achar as soluções para os problemas. As dificuldades em programação sempre vão existir! No início você irá se deparar com dificuldade em tarefas simples que com o tempo se tornarão naturais de se programar, mas surgirão novas dificuldades em tarefas mais complexas.
O importante no final das contas, é manter-se motivado, sentir-se realizado pelas pequenas conquistas e buscar suporte e materiais de qualidade para consulta. A intenção do site Neo traderBot é justamente ter um ambiente colaborativo com materiais de relevância e pessoas interessadas em ajudar umas as outras na busca por soluções.
Espero que tenha gostado do curso, mas se há alguma sugestão ou critíca para que possamos melhorar o conteúdo, não hesite em comentar abaixo.
Muito obrigado e sucesso para você nessa jornada de conhecimento!