Parte 2
Na parte 1 foi apresentado o carregamento do dataframe da variável df_m1m9a22, com os dados das cotações de 2022 da B3/BOVESPA, de janeiro ao início de outubro de 2022.
Também foram apresentados gráficos 2D de linhas, bollinger e histogramas.
Na Parte 2, mostramos gráficos 3D e correlações.
Os gráficos 3D de linhas, barras ou dispersão, plotam nos eixos x, y e z, em três dimensões, os dados de três séries obtidas do dataframe.
As correlações indicam a interdependência no comportamento, ao longo de um período, entre séries com diferentes tendências de altas e baixas de seus valores.
Importamos os pacotes necessários:
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
Configuramos o Pandas para imprimir valores reais com duas casas decimais.
pd.options.display.float_format = "{:.2f}".format
O módulo pyplot tem funções para a plotagem em 3D de gráficos de linhas com marcadores, gráficos de barras e gráficos de dispersão.
Para uma demonstração preliminar dessas funções, criamos um dataframe só com cotações do código de negociação VALE3.
df_vale3 = df_m1m9a22[df_m1m9a22["CODNEG"] == "VALE3"]
Criamos duas séries com as colunas do dataframe de volume total e último preço.
sr_vale3_pu = df_vale3["PREULT"]
sr_vale3_vt = df_vale3["VOLTOT"]
Usaremos nas plotagens as séries sr_vale3_vt e sr_vale3_pu como argumentos dos eixos y e z, respectivamente.
Criamos a série do eixo x com a sequência numérica dos pregões, de 1 até o tamanho da série y (que também é o tamanho da série z).
sr_x = [x+1 for x in list(range(len(sr_vale3_vt)))]
Exemplo de gráfico 3D com linhas sólidas e sem marcadores, usando sr_x em x, sr_vale3_vt em y e sr_vale3_pu em z.
ax = plt.figure().add_subplot(projection='3d')
ax.plot3D(sr_x, sr_vale3_vt, sr_vale3_pu)
plt.show()
NameError: name 'sr_x' is not defined Exemplo de gráfico 3D com linhas pontilhadas e asteriscos como marcadores nas posições de coordenadas.
ax = plt.figure().add_subplot(projection='3d')
ax.plot3D(sr_x, sr_vale3_vt, sr_vale3_pu,marker="*",linestyle="dotted")
plt.show()
NameError: name 'sr_x' is not defined Exemplo de gráfico 3D de linhas transparentes e marcadores esféricos nas coordenadas, similar a um gráfico de dispersão.
ax = plt.figure().add_subplot(projection='3d')
ax.plot3D(sr_x, sr_vale3_vt, sr_vale3_pu,marker="o",linestyle="")
plt.show()
NameError: name 'sr_x' is not defined O gráfico de linhas produzido com a função plot3D, sem as linhas e com marcadores, é semelhante ao gráfico de dispersão (scatter).
O gráfico de dispersão produzido com a função scatter() tem marcadores com diferentes intensidades de transparência.
A mensagem é a de que, quanto mais transparente o marcador do ponto estiver, mais distante o ponto estará em termos de coordenadas x, y e z na projeção 3D.
ax = plt.figure().add_subplot(projection='3d')
ax.scatter(sr_x, sr_vale3_vt, sr_vale3_pu)
plt.show()
NameError: name 'sr_x' is not defined Declaramos funções que utilizaremos na produção de gráficos 2D e 3D de diferentes tipos: linhas com marcadores, barras e dispersão.
São as seguintes:
Com estas funções podemos criar gráficos 2D ou 3D, com uma ou duas partes, chamadas subplots, plotando diferentes desenhos.
Chamamos desenhos as linhas, marcadores, barras e dispersões plotadas nos gráficos.
Usamos as variáveis ax1 e ax2 apontando para os subplots do gráfico.
Nesses subplots plotamos diferentes tipos de gráficos.
As funções do módulo pylplot para plotagem de gráficos 2D são plot(), bar() e scatter().
Utilizamos o argumento projection="3d" na função add_subplot do pyplot para o subplot plotar em 3D.
As funções do pyplot para plotagem de gráficos 3D são plot3D(), bar3D() e scatter(), com o subplot projetando em 3D.
Analise o código das funções cieda_b3_plot_2D3D(), cieda_b3_subplot_2D3D() e cieda_b3_show_2D3D() para entender as combinações realizadas pelas funções, com diferentes tipos de projeção (2D e 3D), tipos de gráficos (plot, bar, scatter) e partes (subplots).
A função cieda_b3_plot_2D3D() plota o dataframe com as colunas de colx, coly e colz e o código de negociação codneg.
def cieda_b3_plot_2D3D(
df, ax1, ax2, colx, coly, colz, codneg,
tipo, projecao, marker, linestyle,
titulo, xlabel, grade, leg):
#
dfaux = df[df["CODNEG"] == codneg]
x = [x+1 for x in list(range(len(dfaux)))]
#x = dfaux[colx] if colx else list(range(len(dfaux)))
y = dfaux[coly]
z = dfaux[colz] if colz else None
def desenhar(
ax = ax1,
x = x,
y = y,
z = z,
tipo = "plot",
projecao = projecao,
label = codneg,
titulo = titulo,
xlabel = xlabel,
ylabel = coly,
zlabel = colz,
grade = grade,
leg = True,
marker = marker,
linestyle = linestyle,
alpha = 1):
#
ax.set_title(titulo)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
if zlabel: ax.set_zlabel(zlabel)
if grade: ax.grid(visible=True)
#if leg: ax.legend()
if projecao == "2D":
if tipo == "plot":
ax.plot(x,y,label=label,marker=marker,linestyle=linestyle,alpha=alpha)
elif tipo == "bar":
ax.bar(x,y,label=label,alpha=alpha)
elif tipo == "barh":
ax.barh(x,y,label=label,alpha=alpha)
elif tipo == "scatter":
ax.scatter(x,y,label=label)
elif projecao == "3D":
if tipo == "plot":
ax.plot3D(x,y,z,label=label,marker=marker,linestyle=linestyle,alpha=alpha)
elif tipo == "bar":
zeros = np.zeros(len(x))
uns = np.ones(len(x))
meios = uns * 0.5
ax.bar3d(x,y,zeros,meios,uns,z,label=label,alpha=alpha)
elif tipo == "scatter":
ax.scatter(x,y,z,label=label)
#
if projecao == "2D":
if tipo == "plot":
desenhar()
elif tipo == "bar":
desenhar(tipo="bar",alpha=0.5)
elif tipo == "barh":
desenhar(tipo="barh",alpha=0.5)
elif tipo == "scatter":
desenhar(tipo="scatter")
elif tipo == "plot_scatter":
desenhar()
desenhar(ax=ax2,tipo="scatter",y=z,ylabel=colz,titulo="",xlabel="")
elif tipo == "scatter_bar":
desenhar(tipo="scatter")
desenhar(ax=ax2,tipo="bar",y=z,ylabel=colz,titulo="",xlabel="")
elif projecao == "3D":
if tipo == "plot":
desenhar()
elif tipo == "bar":
desenhar(tipo="bar",leg=False,alpha=0.5)
elif tipo == "scatter":
desenhar(tipo="scatter")
elif tipo == "plot2":
desenhar(zlabel="",projecao="2D")
desenhar(ax=ax2,y=z,titulo="",xlabel="",ylabel=colz,zlabel="",projecao="2D")
elif tipo == "bar2":
desenhar(tipo="bar",zlabel="",projecao="2D",alpha=0.5)
desenhar(ax=ax2,y=z,tipo="bar",titulo="",xlabel="",ylabel=colz,zlabel="",leg=False,projecao="2D",alpha=0.5)
elif tipo == "scatter2":
desenhar(tipo="scatter",zlabel="",projecao="2D")
desenhar(ax=ax2,y=z,tipo="scatter",titulo="",xlabel="",ylabel=colz,zlabel="",leg=False,projecao="2D")
elif tipo == "plot_scatter":
desenhar()
desenhar(ax=ax2,tipo="scatter",titulo="",xlabel="",leg=False)
elif tipo == "scatter_bar":
desenhar(tipo="scatter")
desenhar(ax=ax2,tipo="bar",titulo="",xlabel="",leg=False, alpha=0.5)
A função cieda_b3_subplot_2D3D() prepara as áreas de plotagem no gráfico, com uma ou duas partes, em formato 2D ou 3D.
Se a projeção for 2D e o tipo for plot_scatter são adicionado dois subplots 2D em ax1 e ax2, senão é adicionado um subplot 2D em ax1.
Se a projeção for 3D e o tipo for plot_scatter ou scatter_bar são adicionados dois subplots em 3D em ax1 e ax2.
Se for plot2, bar2 ou scatter2 são usados dois subplots em 2D em ax1 e ax2.
Caso contrário é adicionado apenas um subplot 3D em ax1.
def cieda_b3_subplot_2D3D(tipo,projecao,figsize):
fig = plt.figure(figsize=figsize)
if projecao == "2D":
if tipo == "plot_scatter":
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
else:
ax1 = fig.add_subplot()
ax2 = None
elif projecao == "3D":
if tipo == "plot_scatter" or tipo == "scatter_bar":
ax1 = fig.add_subplot(1,2,1,projection='3d')
ax2 = fig.add_subplot(1,2,2,projection='3d')
elif tipo == "plot2" or tipo == "bar2" or tipo == "scatter2":
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
else:
ax1 = fig.add_subplot(projection='3d')
ax2 = None
return fig, ax1, ax2
A função cieda_b3_show_2D3D() plota as séries e mostra o gráfico do dataframe df, com as colunas de xyz, os códigos de negociações de codnegs, e a faixa de datas de dataini a datafim.
def cieda_b3_show_2D3D(
df, xyz, codnegs,
dataini = -1,
datafim = -1,
sobrepor = False,
figsize = (16,16),
tipo = "plot",
projecao = "2D",
marker = "o",
linestyle = "dotted",
grade = False,
leg = True):
#
lista_xyz = xyz.split(",")
tam = len(lista_xyz)
colx = lista_xyz[0] if tam > 0 else None
coly = lista_xyz[1] if tam > 1 else None
colz = lista_xyz[2] if tam > 2 else None
campos = "CODNEG,DMAPRE,{},{}".format(colx,coly)
if colz:
projecao = "3D"
campos += "," + colz
else:
projecao = "2D"
dfaux = cieda_b3_df_cndp(df,campos,codnegs,dataini,datafim)
data_inicial = dfaux["DMAPRE"].iloc[0]
data_final = dfaux["DMAPRE"].iloc[-1]
xlabel = "Pregões de {} a {}".format(data_inicial,data_final)
codnegs_unicos = dfaux["CODNEG"].unique()
titulo = "CODNEG: "+", ".join(codnegs_unicos)
if sobrepor:
fig, ax1, ax2 = cieda_b3_subplot_2D3D(tipo,projecao,figsize)
for codneg in codnegs_unicos:
if not sobrepor:
titulo = "CODNEG: " + codneg
fig, ax1, ax2 = cieda_b3_subplot_2D3D(tipo,projecao,figsize)
cieda_b3_plot_2D3D(dfaux,ax1,ax2,colx,coly,colz,codneg,tipo,projecao,marker,linestyle,titulo,xlabel,grade,leg)
if not sobrepor:
if not ((tipo == "bar") and (projecao == "3D")): ax1.legend()
plt.show()
if sobrepor:
if not ((tipo == "bar") and (projecao == "3D")): ax1.legend()
plt.show()
Utilizamos a função cieda_b3_show_2D3D com o dataframe df_m1m9a22, usando as séries das colunas AMDPRE, VOLTOT e PREULT.
Observe dois gráficos sem sobreposição dos códigos de negociação VALE3 e PETR4.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR4",
tipo="scatter")
NameError: name 'df_m1m9a22' is not defined Observe um gráfico com as séries sobrepostas dos códigos de negociação VALE3, PETR3, PETR4, USIM3, BBDC3 e BBDC4.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
sobrepor=True,
tipo="scatter")
NameError: name 'df_m1m9a22' is not defined Com o tipo scatter2 plotamos as 3 dimensões combinadas como x e y e x e z em dois subplots 2D.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3",
figsize=(16,8),
grade=True,
tipo="scatter2")
NameError: name 'df_m1m9a22' is not defined Gráficos 3D de linhas sem marcadores, não sobrepostos, dos códigos de negociação VALE3 e PETR4, cruzando as variáveis pregões, volume total e último preço.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR4")
NameError: name 'df_m1m9a22' is not defined Gráfico 3D de linhas sobrepondo as plotagens dos códigos de negociação VALE3, PETR3, PETR4, USIM3, BBDC3 e BBDC4, cruzando as variáveis pregões, volume total e último preço.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
sobrepor=True)
NameError: name 'df_m1m9a22' is not defined Com o tipo plot_scatter plotamos os gráfico de linhas ao lado do gráfico de dispersão em dois subplots 3D.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3",
tipo="plot_scatter",
figsize=(16,8))
NameError: name 'df_m1m9a22' is not defined Com o tipo plot2 plotamos as 3 dimensões combinadas como x e y e x e z em dois subplots 2D.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3",
tipo="plot2",
grade=True,
figsize=(16,8))
NameError: name 'df_m1m9a22' is not defined Gráficos 3D de barras, não sobrepostos, dos códigos de negociação VALE3 e PETR4, cruzando as variáveis pregões, volume total e último preço.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR4",
tipo="bar")
NameError: name 'df_m1m9a22' is not defined Gráfico 3D de barras sobrepondo as plotagens dos códigos de negociação VALE3, PETR3, PETR4, USIM3, BBDC3 e BBDC4, cruzando as variáveis pregões, volume total e último preço.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
sobrepor=True,
tipo="bar")
NameError: name 'df_m1m9a22' is not defined O gráfico de barras 3D não tem legenda e para contornar essa limitação podemos imprimir, usando o tipo scatter_bar, o gráfico de barras junto com o gráfico de dispersão contendo a legenda.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
sobrepor=True,
figsize=(20,10),
tipo="scatter_bar")
NameError: name 'df_m1m9a22' is not defined Vamos criar o gráfico 3D com menos barras usando um período menor, de três meses, com os pregões de julho a setembro de 2022.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
2207,2209,
sobrepor=True,
figsize=(20,10),
tipo="scatter_bar")
NameError: name 'df_m1m9a22' is not defined Vamos criar o gráfico 3D com menos barras ainda, usando um período de apenas um mês, com os pregões de agosto de 2022.
cieda_b3_show_2D3D(
df_m1m9a22,
"AMDPRE,VOLTOT,PREULT",
"VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4",
2208,
sobrepor=True,
figsize=(20,10),
tipo="scatter_bar")
NameError: name 'df_m1m9a22' is not defined Correlações são correspondências, similaridades, analogias entre pessoas, coisas, ideias relacionadas entre si.
Na Estatística é a interdependência de duas ou mais variáveis.
A função corr() do dataframe Pandas retorna as correlações entre as suas colunas númericas.
Estas correlações são valores reais fracionários entre 0 e 1 (zero e um), com:
0 <= interdependência <= 1
Distribuimos as correlações por faixas:
FAIXA | DE | ATÉ |
---|---|---|
baixa | 0.0 | 0.2 |
média-baixa | 0.2 | 0.4 |
média | 0.4 | 0.6 |
média-alta | 0.6 | 0.8 |
alta | 0.8 | 1.0 |
Vamos analisar, em um pequeno estudo sobre exercícios físicos, as correlações entre as variáveis tempo, calorias e batimentos, respectivamente o tempo de exercício, as calorias queimadas e os batimentos por minuto de 10 atletas após se exercitarem.
df_exercicio = pd.DataFrame({
"tempo" : [ 45, 60, 45, 45, 45, 90, 60, 60, 45, 60],
"calorias" : [470, 610, 440, 480, 410, 930, 440, 640, 480, 630],
"batimentos" : [120, 90, 136, 110, 127, 122, 98, 140, 138, 112]
})
print(df_exercicio)
Imprimimos as correlações entre as variáveis tempo, calorias e batimentos .
corr = df_exercicio.corr()
print(corr)
Imprimimos o tipo da variável para sabermos de que tipo é o objeto de correlações.
print(type(corr))
Observamos que existe uma correlação alta (0.8 a 1.0) entre tempo de exercício e calorias queimadas, o que faz sentido, pois quanto mais tempo a pessoa se exercita, mais calorias queima.
A correlação é causal, pois a quantidade de calorias queimadas depende do tempo dedicado aos exercícios físicos: quanto mais tempo dedicado, maior a quantidade de calorias queimadas.
Observamos uma correlação média-baixa (0.2 a 0.4) entre o tempo de exercício e os batimentos por minuto, pois estes não variam além de uma faixa conhecida de frequência.
Independente do tempo dedicado à prática de exercícios físicos, os batimentos por minuto estarão sempre dentro dessa faixa.
Iremos a seguir imprimir as correlações de diferentes dataframes usando as colunas PREABE, PREMAX, PREMIN, PREULT, TOTNEG, QUATOT, VOLTOT e AMDPRE.
Trabalharemos com precisão decimal de 3 casas, pois os valores de correlação são números reais fracionários entre 0 e 1.
Configuramos o Pandas para imprimir valores reais com 3 casas decimais.
pd.options.display.float_format = "{:.3f}".format
A variável corr1 recebe a correlação do dataframe df_m1m9a22, usando todas as cotações, de todos códigos de negociação, nas datas de janeiro a setembro do ano de 2022.
df_corr = df_m1m9a22[["PREABE","PREMAX","PREMIN","PREULT","TOTNEG","QUATOT","VOLTOT","AMDPRE"]].corr()
Imprimimos as correlações.
print(df_corr)
Observamos uma correlação alta (0.8 a 1.0) entre as séries de preços PREABE, PREMAX, PREMIN e PREULT.
Os valores das correlações estão bem próximos de 1, valor máximo, o que faz sentido, pois estas variáveis variam para cima e para baixo, diariamente, com comportamento semelhante.
Observamos que praticamente não há correlação dessas com QUATOT, TOTNEG e VOLTOT, pois os valores estão muito próximos de 0 (zero).
A correlação média (0.4 a 0.6) entre VOLTOT e QUATOT indica certa relação entre as movimentações das variáveis.
A relação média-baixa (0.2 a 0.4) entre VOLTOT e TOTNEG, indica que as oscilações de alta e baixa de uma e outra têm pouca relação, apesar da existência da tendência do volume total aumentar com mais negócios.
O baixo valor da correlação entre as variáveis sinaliza que o volume total movimentado, independente do número de negócios.
Um grande volume pode ser atingido com menos negócios, se a quantidade negociada por negócio for alta.
A seguir a variável df_aux1 recebe o dataframe só com as cotações do código de negociação VALE3, de janeiro a setembro do ano de 2022.
df_aux1 = cieda_b3_df_cndp(
df_m1m9a22,
"PREABE,PREMAX,PREMIN,PREULT,TOTNEG,QUATOT,VOLTOT,AMDPRE",
"VALE3")
print(df_aux1)
Retornamos em df_corr2 o dataframe com as correlações de df_aux2.
df_corr1 = df_aux1.corr()
print(df_corr1)
Observe que, para as cotações no ano de 2022 do código de negociação VALE3, as correlações entre as variáveis de preço diminuiram, indicando determinado desacoplamento entre os preços de abertura, preço máximo, preço mínimo e último preço.
Interessante observar uma correlação média-alta (0.6 a 0.8) negativa das variáveis de preço e a data do pregão (variável AMDPRE) indicando que houve no período uma relação direta entre o tempo decorrido na forma de pregões com a queda forte dos preços, num movimento consistente de queda, embora o tempo não seja a causa da queda nos preços.
A seguir a variável df_aux2 recebe o dataframe apenas com os papéis do código de negociação VALE3 de agosto do ano de 2022.
df_aux2 = cieda_b3_df_cndp(
df_m1m9a22,
"PREABE,PREMAX,PREMIN,PREULT,TOTNEG,QUATOT,VOLTOT,AMDPRE",
"VALE3",
2208)
print(df_aux2)
Retornamos em df_corr2 o dataframe com as correlações de df_aux2.
df_corr2 = df_aux2.corr()
print(df_corr2)
Observamos uma menor correlação negativa entre as variáveis de preços e a data, indicando, nesse período, já no terceiro trimestre do ano, comportamento de queda do papel, mas estabelecendo uma relação menor entre preços e tempo transcorrido.
Concluimos que as altas e baixas das variáveis de preços oscilam de modo independente do tempo.
Observamos também uma correlação menor entre as variáveis de preço, indicando que variaram - entre si - de forma mais heterogênea.
Por exemplo, com o preço máximo nos pregões variando para cima ou para baixo com maiores ou menores variações, a cada dia, em relação ao último preço.
Algumas vezes pouco mais, outras muito mais, outras vezes muito menos e ainda pouco menos.
Agora vamos montar um dataframe df_merge contendo com as colunas AMDPRE, VALE3, PETR3, PETR4 e USIM3.
A coluna AMDPRE contém a série com as data dos pregões e as colunas VALE3, PETR3, PETR4 e USIM3 contêm as séries com os valores de último preço desses códigos de negociação.
A função cieda_b3_montar_tabela() monta um dataset com a coluna indicada, retornando um dataframe com a data da cotação e as colunas com as séries dos códigos de negociação selecionados.
def cieda_b3_montar_tabela(df, col, codnegs, dataini=-1, datafim=-1):
dfaux1 = cieda_b3_df_cndp(df,"CODNEG,AMDPRE,{}".format(col),codnegs,dataini,datafim)
np_codnegs_unicos = dfaux1["CODNEG"].unique()
np_datas_unicas = dfaux1["AMDPRE"].unique()
df_merge = pd.DataFrame({"AMDPRE": np_datas_unicas})
for codneg in np_codnegs_unicos:
dfaux2 = dfaux1[dfaux1["CODNEG"] == codneg]
dfaux3 = dfaux2[["AMDPRE",col]]
dfaux3.columns = ["AMDPRE",codneg]
df_merge = pd.merge(df_merge,dfaux3)
return df_merge
Atribuimos na variável df_merge o resultado da função cieda_b3_montar_tabela com o dataframe das séries dos códigos de negociação nas colunas do dataframe.
df_merge = cieda_b3_montar_tabela(df_m1m9a22,"PREULT","VALE3,PETR3,PETR4,USIM3,BBDC3,BBDC4")
print(df_merge)
Imprimimos as correlações.
corr = df_merge.corr()
print(corr)
O Python permite a produção de gráficos 3D que permitem a leitura de informações com clareza, de diferentes formas: com gráficos de linhas e marcadores, com gráficos de barras ou gráficos de dispersão.
A correlação entre as colunas numéricas das cotações também trazem diversas leituras das informações.
As possibilidades de visualização de informações dos dados são muitas, e serão apresentadas continuamente nos capítulos seguintes, de acordo com o seguinte planejamento:
CONTATO:
Para receber a versão PDF, tirar dúvidas ou fazer contato conosco envie email para atendimento@cieda.com.br.