master 97845a531dfb cached
40 files
68.5 KB
18.9k tokens
17 symbols
1 requests
Download .txt
Repository: daniloaleixo/bovespaStockRatings
Branch: master
Commit: 97845a531dfb
Files: 40
Total size: 68.5 KB

Directory structure:
gitextract_nx7a1d76/

├── .gitignore
├── .gitmodules
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Pipfile
├── Procfile
├── Procfile.windows
├── README.md
├── app.json
├── client/
│   ├── getFromFirebase.js
│   └── styles.css
├── docker-compose.yml
├── functions/
│   ├── .gitignore
│   ├── package.json
│   ├── src/
│   │   └── index.ts
│   ├── tsconfig.json
│   └── tslint.json
├── fundamentus.py
├── gettingstarted/
│   ├── __init__.py
│   ├── settings.py
│   ├── static/
│   │   └── humans.txt
│   ├── urls.py
│   └── wsgi.py
├── hello/
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── db.html
│   │   └── index.html
│   ├── tests.py
│   └── views.py
├── index.html
├── manage.py
├── requirements.txt
├── services.sh
└── waitingbar.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
__pycache__/*
scripts/__pycache__/*
firebase.json
.env
Pipfile.lock

================================================
FILE: .gitmodules
================================================
[submodule "fundamentalAnalysisHistoricalDataClient"]
	path = fundamentalAnalysisHistoricalDataClient
	url = https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataClient.git
	branch = master
[submodule "fundamentalAnalysisHistoricalDataServer"]
	path = fundamentalAnalysisHistoricalDataServer
	url = https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataServer.git
	branch = master


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at danilo_aleixo@hotmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change. 

Please note we have a code of conduct, please follow it in all your interactions with the project.

## Pull Request Process

1. Ensure any install or build dependencies are removed before the end of the layer when doing a 
   build.
2. Update the README.md with details of changes to the interface, this includes new environment 
   variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
   Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 
   do not have permission to do that, you may request the second reviewer to merge it for you.

## Code of Conduct

### Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

### Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

### Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

### Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

### Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

### Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: Dockerfile
================================================
FROM python


COPY fundamentus.py /data/fundamentus.py
COPY waitingbar.py /data/waitingbar.py
WORKDIR /data

# RUN pip install -r requirements.txt
RUN pip install --upgrade lxml && \
    pip install --upgrade python_jwt && \
    pip install --upgrade gcloud && \
    pip install --upgrade sseclient && \
    pip install --upgrade Crypto && \
    pip install --upgrade pycryptodome==3.4.3 && \
    pip install --upgrade requests_toolbelt && \
    pip install --upgrade pymongo && \
    pip install sendgrid && \
    python -m pip install pymongo[srv]

CMD python3 fundamentus.py

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 phoemur

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Pipfile
================================================
[[source]]

url = "https://pypi.python.org/simple"
verify_ssl = true


[packages]

django = "*"
gunicorn = "*"
django-heroku = "*"


[requires]

python_version = "3.6"


================================================
FILE: Procfile
================================================
web: gunicorn gettingstarted.wsgi


================================================
FILE: Procfile.windows
================================================
web: python manage.py runserver 0.0.0.0:5000


================================================
FILE: README.md
================================================
# Bovespa Stock Ratings

Projeto de análise de dados fundamentalistas da Bovespa

**If you like this project you can support me.**  
<div>
<a href="https://apoia.se/daniloaleixo-bovespa" target="_blank"><img src="https://i.imgur.com/mFoBjIN.png" alt="Apoia.se" style="height: 51px !important;width: 217px !important;" ></a>
</div>


## Sobre 
O projeto consiste na primeira fonte de informaçôes open-source sobre análise fundamentalista das ações da Bovespa.
O objetivo é juntar informaçôes para tomadas de decisões.

## Estrutura do projeto

O projeto consiste de 4 projetos em repositórios separados:
* [Crawler](https://github.com/daniloaleixo/bovespaStockRatings): script em python que faz um scrapping em algumas páginas para colher as informações para salvar em um banco de dados Mongo.
* [Backend](https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataServer): Backend que faz a interface, usando GraphQL entre o banco e o front-end.
* [Front-end](https://github.com/daniloaleixo/fundamentalAnalysisHistoricalDataClient): Visualização de dados da aplicação feita, totalmente em Angular.
* [Agente de trading](https://github.com/daniloaleixo/NeuroEvolutionMarketTrader): Agente usando neuro evolução para comprar e vender ações automaticamente


## Configurando o projeto

  
Clonar o repositório principal
```
git clone --recursive git@github.com:daniloaleixo/bovespaStockRatings.git
```

[Opcional] Se quiser clonar o subrepositórios
```
git submodule update --init --recursive
```
  
## Rodando o crawler

### Rodando da imagem docker oficial
```
docker run -e MONGO_URI=$MONGO_URI daniloaleixo/bovespa-stock-ratings-crawler
```
### Fazendo o build da imagem docker
```
docker build -t bovespa_stock_ratings .
docker run -e MONGO_URI=$MONGO_URI -t bovespa_stock_ratings
```



## Análise 
Estou fazendo uma análise baseada nos princípios fundamentalistas do livro [Investidor Inteligente](https://en.wikipedia.org/wiki/The_Intelligent_Investor) do Benjamin Graham:

* Tamanho Adequado 
  * Patrimônio Líquido maior que R$2bi
* Posição Financeira Forte
  * Liquidez Corrente maior que 1,5
  * Dívida Bruta / Patrimônio Líquido < 50%
* Histórico de Dividendos contínuos por, pelo menos, os últimos 20 anos.
  * Ainda não consegui pegar essa informação, estou colocando só o último DY
  * Ultimo DY maior que 2.5%
* Estabilidade nos Ganhos, Nenhum prejuízo nos últimos 10 anos.
  * Ainda não consegui verificar se teve algum prejuízo
* Crescimento nos Ganhos: 10 anos de crescimento nos lucros-por-ação de, pelo menos,
um terço.
  * Ainda não consegui colocar essa informação, mas tenho só 
  * Crescimento no últimos 5 anos maior que 5%
  * ROE > 20%
* Preço sobre Valor de Mercado: O preço da ação inferior a 1,5 x o valor dos ativos
líquidos.
  * P/VPA < 1.5
* P/L Moderado: O preço da ação inferior a 15x o lucro dos últimos 3 anos
  * P/L < 15
* Teste alternativo: Graham multiplicava o P/L pelo preço sobre o valor de mercado e
verifica se o resultado está abaixo de 22.5
  * P/L x P/VPA < 22.5

## Credits
The project was inicially a contribution to this repostory: https://github.com/phoemur/fundamentus


================================================
FILE: app.json
================================================
{
  "name": "Start on Heroku: Python",
  "description": "A barebones Python app, which can easily be deployed to Heroku.",
  "image": "heroku/python",
  "repository": "https://github.com/heroku/python-getting-started",
  "keywords": ["python", "django" ],
  "addons": [ "heroku-postgresql" ],
  "env": {
    "SECRET_KEY": {
      "description": "The secret key for the Django application.",
      "generator": "secret"
    }
  },
  "environments": {
    "test": {
      "scripts": {
        "test-setup": "python manage.py collectstatic --noinput",
        "test": "python manage.py test"
      }
    }
  }
}


================================================
FILE: client/getFromFirebase.js
================================================
// 
// Get info from frebase and show it on the datatable
// 



var database = firebase.database();
var arrayStocksHistory = [];

var resultadoClone;

var lastUpdate;

var comparadores = {
	patrLiq: { value: 2000000000, checked: 1 },
	liqCorr: { value: 1.5, checked: 1 },
	roe: { value: 20, checked: 1 },
	divPat: { value: 50, checked: 1 },
	cresc: { value: 5, checked: 1 },
	pvp: { value: 1.5, checked: 1 },
	pl: { value: 15, checked: 1 },
	dy: { value: 2.5, checked: 1 },
	plxpvp: { value: 22.5, checked: 1 },
}

initInputs();


// *******************************
// 			Logic functions
// *******************************
database.ref().child('stocks').once('value').then(function(snapshot){
	// console.log(snapshot.val())

	Object.keys(snapshot.val()).forEach(function(key){
		// console.log(snapshot.val()[key])
		var object = JSON.parse(snapshot.val()[key]);
		arrayStocksHistory.push(object)
		// console.log(object);
	})

	// Sort by date, the first one will be the newest
	arrayStocksHistory.sort(function(a,b){
		var date1 = new Date(a.date);
		var date2 = new Date(b.date);
		return date2 - date1;
	})

	// console.log(arrayStocksHistory);
	buildTable(arrayStocksHistory[0]);
	hideLoading();

}, function(error){
	console.log("deu erro");
})

// Get last update
database.ref().child('last_date').once('value').then(function(snapshot){

	lastUpdate = Object.keys(snapshot.val())
	.map(function(key){
		return new Date(snapshot.val()[key]);
	})
	.sort(function(a, b) {
		console.log(new Date(a), new Date(b), new Date(a) > new Date(b));
		return new Date(b) > new Date(a) ? 1 : -1;
	})[0];

	$("#lastUpdate").append(lastUpdate);

}, function(error){
	console.log("deu erro");
})



var buildTable = function(data){
	// console.log('vamos montar a tabela', data);

	// Put the objects in an array
	arrayObjects = [];
	Object.keys(data).forEach(function(key){
		arrayObjects.push(data[key])
	});

	arrayObjects = calculateScores(arrayObjects);

	var resultArray = []; 
	arrayObjects
	.forEach(function(element) {
		var innerObject = {};

		if(Object.keys(element).pop().length > 3) {
			Object.keys(element).map(function(innerKey) {
				innerObject = element[innerKey];
				innerObject['papel'] = innerKey;
			});

			var myArray = [];

			myArray.push(innerObject["papel"]);
			myArray.push(innerObject["nota"]);
			myArray.push(innerObject["cotacao"]);
			myArray.push(innerObject["Pat.Liq"]);
			myArray.push(innerObject["Liq.Corr."]);
			myArray.push(innerObject["ROE"]);
			myArray.push(innerObject["Div.Brut/Pat."]);
			myArray.push(innerObject["Cresc.5a"]);
			myArray.push(innerObject["P/VP"]);
			myArray.push(innerObject["P/L"]);
			myArray.push(innerObject["DY"]);
			myArray.push(innerObject["PSR"]);
			myArray.push(innerObject["P/Ativo"]);
			myArray.push(innerObject["P/Cap.Giro"]);
			myArray.push(innerObject["P/EBIT"]);
			myArray.push(innerObject["P/Ativ.Circ.Liq."]);
			myArray.push(innerObject["EV/EBIT"]);
			myArray.push(innerObject["EBITDA"]);
			myArray.push(innerObject["Mrg.Liq."]);
			myArray.push(innerObject["ROIC"]);
			myArray.push(innerObject["Liq.2m."]);
			resultArray.push(myArray);
			
		}

	});
	$('#resultado').DataTable({ 
		'data': resultArray,
		'order'	: [[ 1, "desc" ]], // Order by score
 		"pageLength": 500, // All stocks in the page
 		"createdRow": function( row, data, dataIndex ) {
 			if(data[1] >= 7.5) {
 				$(row).css('background-color', '#cde0cd')
 			}
 		}
	});

	// var txt = "";
	// for(var i = 0; i < arrayObjects.length; i++) {
	// 	if(typeof(arrayObjects[i]) == "object"){

	// 		Object.keys(arrayObjects[i]).forEach(function(stock){

	// 			var greenLine = " class='green-line'";
	// 			// If we see a stock with score below 7.5 we turnoff green
	// 			if(parseFloat(arrayObjects[i][stock]["nota"]) < 7.5)
	// 				greenLine = '';

	// 			var stockLine = "<tr" + greenLine + ">" + 
	// 							"<td class='stock'>" + stock + "</td>" + 
	// 			            	"<td>" + arrayObjects[i][stock]["nota"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["cotacao"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Pat.Liq"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Liq.Corr."] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["ROE"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Div.Brut/Pat."] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Cresc.5a"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/VP"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/L"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["DY"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["PSR"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/Ativo"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/Cap.Giro"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/EBIT"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["P/Ativ.Circ.Liq."] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["EV/EBIT"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["EBITDA"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Mrg.Liq."] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["ROIC"] + "</td>" +
	// 			            	"<td>" + arrayObjects[i][stock]["Liq.2m."] + "</td>" +
	// 			        		"</tr>";

	// 							txt += stockLine;
	// 		})
	// 	}
	// }
	// $(function(){
	// 	$(".table-body").append(txt);
	// 	console.log('estou aqui');
	// 	// $("#resultado").append('dsajdhayasyusadd');
	// })
}

var calculateScores = function(stockArray){
	console.log('calculando socres');
	let dividePor = 0;
	Object.keys(comparadores).forEach(function(elem){
		if(comparadores[elem].checked) dividePor += 1;
	})
	console.log('dividePor', dividePor);

	for(var i = 0; i < stockArray.length; i++) {
		if(typeof(stockArray[i]) == "object"){
			Object.keys(stockArray[i]).forEach(function(stock){
				var nota = 0.0;

				var patrLiq = parseFloat(stockArray[i][stock]["Pat.Liq"].replace(/\./g, '').replace(/\,/g, '.'));
				if(comparadores.patrLiq.checked &&  patrLiq > parseFloat(comparadores.patrLiq.value))
				    nota = nota + 1
				var liqCorr = parseFloat(stockArray[i][stock]["Liq.Corr."].replace(/\./g, '').replace(/,/g, '.'));
				if(comparadores.liqCorr.checked &&  liqCorr > parseFloat(comparadores.liqCorr.value))
				    nota = nota + 1
				var roe = parseFloat(stockArray[i][stock]["ROE"].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.roe.checked &&  roe > parseFloat(comparadores.roe.value)) 
				    nota = nota + 1
				var divPat = parseFloat(stockArray[i][stock]["Div.Brut/Pat."].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.divPat.checked &&  divPat * 100 < parseFloat(comparadores.divPat.value) && divPat > 0) 
				    nota = nota + 1
				var cresc = parseFloat(stockArray[i][stock]["Cresc.5a"].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.cresc.checked &&  cresc > parseFloat(comparadores.cresc.value)) 
				    nota = nota + 1
				var pvp = parseFloat(stockArray[i][stock]["P/VP"].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.pvp.checked &&  pvp < parseFloat(comparadores.pvp.value) && pvp > 0) 
				    nota = nota + 1
				var pl = parseFloat(stockArray[i][stock]["P/L"].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.pl.checked &&  pl < parseFloat(comparadores.pl.value) && pl > 0) 
				    nota = nota + 1
				var dy = parseFloat(stockArray[i][stock]["DY"].replace(/\./g, '').replace(/\,/g, '.').replace(/%/g, ''));
				if(comparadores.dy.checked &&  dy > parseFloat(comparadores.dy.value)) 
				    nota = nota + 1
				if(comparadores.plxpvp.checked &&  pl * pvp < parseFloat(comparadores.plxpvp.value))
					nota = nota + 1;

				stockArray[i][stock]["nota"] = (parseFloat(nota) / dividePor * 10.0).toFixed(2);

				// console.log([stock, stockArray[i][stock]["nota"], patrLiq, liqCorr, roe, divPat, cresc, pvp, pl, dy])

			});
		}
	}

	return stockArray;
}



// Clears the table
var resetTable = function() {
	if ( $.fn.DataTable.isDataTable('#resultado') ) {
	  $('#resultado').DataTable().destroy();
	}
	console.log("reseta tabela", $(".table-body").html())
}


// *******************************
// 			View state functions
// *******************************
var hideLoading = function(){
	$('#loading-whell').addClass("hidden");
	$('#info').removeClass("hidden");
}


function initInputs(){
	console.log("chamei");
	$(function() {
		$('#patrLiqInput').val(comparadores.patrLiq.value);
		$('#liqCorrInput').val(comparadores.liqCorr.value);
		$('#divPatInput').val(comparadores.divPat.value);
		$('#dyInput').val(comparadores.dy.value);
		$('#crescInput').val(comparadores.cresc.value);
		$('#roeInput').val(comparadores.roe.value);
		$('#pvpInput').val(comparadores.pvp.value);
		$('#plInput').val(comparadores.pl.value);
		$('#plxpvpInput').val(comparadores.plxpvp.value);

		resultadoClone = $(".table-body").clone();
	})
}

// Save rules
$(document).on('click', '#saveRules', function(){

	// Get if checkbox is checked
	comparadores.patrLiq.checked = $('#patrLiqCheckbox:checked').length;
	comparadores.liqCorr.checked = $('#liqCorrCheckbox:checked').length;
	comparadores.roe.checked = $('#roeCheckbox:checked').length;
	comparadores.divPat.checked = $('#divPatCheckbox:checked').length;
	comparadores.cresc.checked = $('#crescCheckbox:checked').length;
	comparadores.pvp.checked = $('#pvpCheckbox:checked').length;
	comparadores.pl.checked = $('#plCheckbox:checked').length;
	comparadores.dy.checked = $('#dyCheckbox:checked').length;
	comparadores.plxpvp.checked = $('#plxpvpCheckbox:checked').length;

	// get new values
	comparadores.patrLiq.value = $('#patrLiqInput').val();
	comparadores.liqCorr.value = $('#liqCorrInput').val();
	comparadores.roe.value = $('#roeInput').val();
	comparadores.divPat.value = $('#divPatInput').val();
	comparadores.cresc.value = $('#crescInput').val();
	comparadores.pvp.value = $('#pvpInput').val();
	comparadores.pl.value = $('#plInput').val();
	comparadores.dy.value = $('#dyInput').val();
	comparadores.plxpvp.value = $('#plxpvpInput').val();

	resetTable();
	buildTable(arrayStocksHistory[0]);

})

================================================
FILE: client/styles.css
================================================
@keyframes App-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

th {
  background: white;
  position: sticky;
  top: 0;
  z-index: 10;
  background: #dddddd;
  cursor: pointer;
}

.hidden{display:none;}

.screen {
  position: relative;
  width: 100%;
  height: 200px;
}


.loading-wrapper {
  position: relative;
}

.loading-wrapper .loading-screen {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10;
    background-color: rgba(250,250,250,0.7);
}

.loading-wheel {
    z-index: 11;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
    border: 8px solid #e3e3e3;
    border-radius: 50%;
    border-top: 8px solid #4e8df9;
    width: 100px;
    height: 100px;
    transform: translateY(-50%);
    -webkit-animation: App-logo-spin 1.5s linear infinite;
    animation: App-logo-spin 1.5s linear infinite;
}

.stock {
  color: #0062ff;
}

.green-line {
  background-color: #cde0cd;
}

================================================
FILE: docker-compose.yml
================================================
version: "3.4"
services:
  mongo:
    network_mode: host
    image: willguitaradmfar/mongo-auth
    environment:
      CREATE_DATABASES: "myapp"
      MONGODB_USER: "mongo_user"
      MONGODB_PASS: "admin123"
    volumes:
      - /var/lib/mongodb:/data/db
    restart: always
    ports:
      - 27017:27017

================================================
FILE: functions/.gitignore
================================================
## Compiled JavaScript files
**/*.js
**/*.js.map

# Typescript v1 declaration files
typings/

node_modules/

================================================
FILE: functions/package.json
================================================
{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "8"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.0.0",
    "mysql": "^2.17.1"
  },
  "devDependencies": {
    "@types/mysql": "2.15.6",
    "tslint": "^5.12.0",
    "typescript": "^3.2.2"
  },
  "private": true
}


================================================
FILE: functions/src/index.ts
================================================
import { Change } from 'firebase-functions';
import { DataSnapshot } from 'firebase-functions/lib/providers/database';
import * as Mysql from 'mysql';

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
// export const helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });

export const saveStockHistory = (change: Change<DataSnapshot>, context = null) => {
  // export const saveStockHistory = functions.database.ref('/stocks')
  //   .onWrite((change: Change<DataSnapshot>, context) => {

  const arrayStocksHistory = [];

  const val = change.after.val;


  	Object.keys(val).forEach((key) => {
      // console.log(snapshot.val()[key])
      var object = JSON.parse(val[key]);
      arrayStocksHistory.push(object)
      // console.log(object);
    })
  
    // Sort by date, the first one will be the newest
    arrayStocksHistory.sort((a,b) => {
      var date1: any = new Date(a.date);
      var date2 : any= new Date(b.date);
      return date2 - date1;
    })



  const conn: Mysql.Connection = Mysql.createConnection({
    host: process.env.DB_ENDPOINT,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DATABASE_NAME,
  });


  query(conn, "show tables", {}).then((res) => {
    console.log(res);

    conn.destroy();
  })
    .catch(err => conn.destroy());


  // Grab the current value of what was written to the Realtime Database.
  console.log('Payload:', change, "Context", context);
  return ['Uppercasing', context, change];
  // const uppercase = original.toUpperCase();
  // You must return a Promise when performing asynchronous tasks inside a Functions such as
  // writing to the Firebase Realtime Database.
  // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
  // return snapshot.ref.parent.child('uppercase').set(uppercase);
  // });
};


async function query<T>(conn: Mysql.Connection, queryString: string, substituionValues: Object): Promise<T> {
  const queryOptions: Mysql.QueryOptions = transformIntoMySQLString(queryString, substituionValues);

  return new Promise<T>((resolve, reject) => {
    conn.query(
      queryOptions,
      (err: Mysql.MysqlError | null, results?: any, fields?: Mysql.FieldInfo[]) => {
        if (err) reject(err);
        else {
          console.info('Salvo objeto com sucesso no DB');
          resolve(results);
        }
      }
    );
  });
}

function transformIntoMySQLString(queryString: string, substituionValues: any): Mysql.QueryOptions {

  // Get all keys (they have a ':' in front of the name)
  const allKeys: string[] = queryString.split(' ')
    .filter((word: string) => word.indexOf(':') == 0);

  const allValuesInOrder: Array<string> = allKeys
    .map((key: string) => substituionValues[key]);

  // In case of error 
  if (allKeys.length != allValuesInOrder.length)
    throw (
      { 'queryString': queryString, subsValues: substituionValues }
    );


  // Overwrite the keys with '?'
  let MysqlQueryString: string = queryString;
  for (const key of allKeys) {
    MysqlQueryString = MysqlQueryString.replace(key, '?');
  }

  return {
    sql: MysqlQueryString,
    values: allValuesInOrder
  };
}


const change: any = null;
// {
//   before:
//     DataSnapshot: {
//       app:
//       FirebaseApp: {
//         firebaseInternals_: [],
//         services_: { },
//         isDeleted_: false,
//         name_: '__admin__',
//         options_: [],
//         INTERNAL: [] },
//   instance: 'https://bovespastockratings.firebaseio.com',
//   _path: '/stocks',
//   _data:
//     {
//       '-LiAHa0uatNefaIDZ250': ' {\n    "0": {\n        "GBIO33": {\n            "Cresc.5a": "0,00%",\n            "DY": "0,00%",\n            "Div.Brut/Pat.": "0,30",\n            "EBITDA": "23,44%",\n            "EV/EBIT": "0,00",\n            "Liq.2m.": "1.360.630,00",\n            "Liq.Corr.": "2,03",\n            "Mrg.Liq.": "7,73%",\n            "P/Ativ.Circ.Liq.": "0,00",\n            "P/Ativo": "0,000",\n            "P/Cap.Giro": "0,00",\n            "P/EBIT": "0,00",\n            "P/L": "0,00",\n            "P/VP": "0,00",\n            "PSR": "0,000",\n            "Pat.Liq": "729.236.000,00",\n            "ROE": "8,70%",\n            "ROIC": "19,69%",\n            "cotacao": "7,25"\n        }\n    },\n    "1": {\n        "STBP3": {\n            "Cresc.5a": "-2,25%",\n            "DY": "0,10%",\n            "Div.Brut/Pat.": "0,16",\n            "EBITDA": "5,32%",\n            "EV/EBIT": "58,74",\n            "Liq.2m.": "6.607.860,00",\n            "Liq.Corr.": "1,23",\n            "Mrg.Liq.": "-0,01%",\n            "P/Ativ.Circ.Liq.": "-2,58",\n            "P/Ativo": "1,024",\n            "P/Cap.Giro": "39,43",\n            "P/EBIT": "59,37",\n            "P/L": "-26.388,80",\n            "P/VP": "2,21",\n            "PSR": "3,161",\n            "Pat.Liq": "1.337.190.000,00",\n            "ROE": "-0,01%",\n            "ROIC": "1,93%",\n            "cotacao": "4,43"\n        }\n    }'
//     }
//   }
// }

saveStockHistory(change);

================================================
FILE: functions/tsconfig.json
================================================
{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017"
  },
  "compileOnSave": true,
  "include": [
    "src"
  ]
}


================================================
FILE: functions/tslint.json
================================================
{
  "rules": {
    // -- Strict errors --
    // These lint rules are likely always a good idea.

    // Force function overloads to be declared together. This ensures readers understand APIs.
    "adjacent-overload-signatures": true,

    // Do not allow the subtle/obscure comma operator.
    "ban-comma-operator": true,

    // Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.
    "no-namespace": true,

    // Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.
    "no-parameter-reassignment": true,

    // Force the use of ES6-style imports instead of /// <reference path=> imports.
    "no-reference": true,

    // Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the
    // code currently being edited (they may be incorrectly handling a different type case that does not exist).
    "no-unnecessary-type-assertion": true,

    // Disallow nonsensical label usage.
    "label-position": true,

    // Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.
    "no-conditional-assignment": true,

    // Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).
    "no-construct": true,

    // Do not allow super() to be called twice in a constructor.
    "no-duplicate-super": true,

    // Do not allow the same case to appear more than once in a switch block.
    "no-duplicate-switch-case": true,

    // Do not allow a variable to be declared more than once in the same block. Consider function parameters in this
    // rule.
    "no-duplicate-variable": [true, "check-parameters"],

    // Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should
    // instead use a separate variable name.
    "no-shadowed-variable": true,

    // Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.
    "no-empty": [true, "allow-empty-catch"],

    // Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.
    // This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.
    "no-floating-promises": true,

    // Do not allow any imports for modules that are not in package.json. These will almost certainly fail when
    // deployed.
    "no-implicit-dependencies": true,

    // The 'this' keyword can only be used inside of classes.
    "no-invalid-this": true,

    // Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.
    "no-string-throw": true,

    // Disallow control flow statements, such as return, continue, break, and throw in finally blocks.
    "no-unsafe-finally": true,

    // Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();
    "no-void-expression": [true, "ignore-arrow-function-shorthand"],

    // Disallow duplicate imports in the same file.
    "no-duplicate-imports": true,


    // -- Strong Warnings --
    // These rules should almost never be needed, but may be included due to legacy code.
    // They are left as a warning to avoid frustration with blocked deploys when the developer
    // understand the warning and wants to deploy anyway.

    // Warn when an empty interface is defined. These are generally not useful.
    "no-empty-interface": {"severity": "warning"},

    // Warn when an import will have side effects.
    "no-import-side-effect": {"severity": "warning"},

    // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for
    // most values and let for values that will change.
    "no-var-keyword": {"severity": "warning"},

    // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.
    "triple-equals": {"severity": "warning"},

    // Warn when using deprecated APIs.
    "deprecation": {"severity": "warning"},

    // -- Light Warnings --
    // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info"
    // if TSLint supported such a level.

    // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.
    // (Even better: check out utils like .map if transforming an array!)
    "prefer-for-of": {"severity": "warning"},

    // Warns if function overloads could be unified into a single function with optional or rest parameters.
    "unified-signatures": {"severity": "warning"},

    // Prefer const for values that will not change. This better documents code.
    "prefer-const": {"severity": "warning"},

    // Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts.
    "trailing-comma": {"severity": "warning"}
  },

  "defaultSeverity": "error"
}


================================================
FILE: fundamentus.py
================================================
#!/usr/bin/env python3

import re
import urllib.request
import urllib.parse
import http.cookiejar
import time
import lxml

from lxml.html import fragment_fromstring
from collections import OrderedDict
import json
import ast
import datetime
import os
from pymongo import MongoClient
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail


def get_data(*args, **kwargs):
    url = 'http://www.fundamentus.com.br/resultado.php'
    cj = http.cookiejar.CookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
    opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201'),
                         ('Accept', 'text/html, text/plain, text/css, text/sgml, */*;q=0.01')]

    # Aqui estão os parâmetros de busca das ações
    # Estão em branco para que retorne todas as disponíveis
    data = {'pl_min':'',
            'pl_max':'',
            'pvp_min':'',
            'pvp_max' :'',
            'psr_min':'',
            'psr_max':'',
            'divy_min':'',
            'divy_max':'',
            'pativos_min':'',
            'pativos_max':'',
            'pcapgiro_min':'',
            'pcapgiro_max':'',
            'pebit_min':'',
            'pebit_max':'',
            'fgrah_min':'',
            'fgrah_max':'',
            'firma_ebit_min':'',
            'firma_ebit_max':'',
            'margemebit_min':'',
            'margemebit_max':'',
            'margemliq_min':'',
            'margemliq_max':'',
            'liqcorr_min':'',
            'liqcorr_max':'',
            'roic_min':'',
            'roic_max':'',
            'roe_min':'',
            'roe_max':'',
            'liq_min':'',
            'liq_max':'',
            'patrim_min':'',
            'patrim_max':'',
            'divbruta_min':'',
            'divbruta_max':'',
            'tx_cresc_rec_min':'',
            'tx_cresc_rec_max':'',
            'setor':'',
            'negociada':'ON',
            'ordem':'1',
            'x':'28',
            'y':'16'}

    with opener.open(url, urllib.parse.urlencode(data).encode('UTF-8')) as link:
        content = link.read().decode('ISO-8859-1')

    pattern = re.compile('<table id="resultado".*</table>', re.DOTALL)
    reg = re.findall(pattern, content)[0]
    page = fragment_fromstring(reg)
    lista = OrderedDict()

    stocks = page.xpath('tbody')[0].findall("tr")

    for i in range(0, len(stocks)):
        lista[i] = {
            stocks[i].getchildren()[0][0].getchildren()[0].text: {
                'cotacao': stocks[i].getchildren()[1].text,
               'P/L': stocks[i].getchildren()[2].text,
               'P/VP': stocks[i].getchildren()[3].text,
               'PSR': stocks[i].getchildren()[4].text,
               'DY': stocks[i].getchildren()[5].text,
               'P/Ativo': stocks[i].getchildren()[6].text,
               'P/Cap.Giro': stocks[i].getchildren()[7].text,
               'P/EBIT': stocks[i].getchildren()[8].text,
               'P/Ativ.Circ.Liq.': stocks[i].getchildren()[9].text,
               'EV/EBIT': stocks[i].getchildren()[10].text,
               'EBITDA': stocks[i].getchildren()[11].text,
               'Mrg. Ebit': stocks[i].getchildren()[12].text,
               'Mrg.Liq.': stocks[i].getchildren()[13].text,
               'Liq.Corr.': stocks[i].getchildren()[14].text,
               'ROIC': stocks[i].getchildren()[15].text,
               'ROE': stocks[i].getchildren()[16].text,
               'Liq.2m.': stocks[i].getchildren()[17].text,
               'Pat.Liq': stocks[i].getchildren()[18].text,
               'Div.Brut/Pat.': stocks[i].getchildren()[19].text,
               'Cresc.5a': stocks[i].getchildren()[20].text
               }
            }


    return lista


def get_specific_data(stock):
    url = "http://www.fundamentus.com.br/detalhes.php?papel=" + stock
    cj = http.cookiejar.CookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
    opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201'),
                         ('Accept', 'text/html, text/plain, text/css, text/sgml, */*;q=0.01')]
    
    # Get data from site
    link = opener.open(url, urllib.parse.urlencode({}).encode('UTF-8'))
    content = link.read().decode('ISO-8859-1')

    # Get all table instances
    pattern = re.compile('<table class="w728">.*</table>', re.DOTALL)
    reg = re.findall(pattern, content)[0]
    reg = "<div>" + reg + "</div>"
    page = fragment_fromstring(reg)
    all_data = {}

    # There is 5 tables with tr, I will get all trs
    all_trs = []
    all_tables = page.xpath("table")

    for i in range(0, len(all_tables)):
        all_trs = all_trs + all_tables[i].findall("tr")

    # Run through all the trs and get the label and the
    # data for each line
    for tr_index in range(0, len(all_trs)):
        tr = all_trs[tr_index]
        # Get into td
        all_tds = tr.getchildren()
        for td_index in range(0, len(all_tds)):
            td = all_tds[td_index]


            label = ""
            data = ""

            # The page has tds with contents and some 
            # other with not
            if (td.get("class").find("label") != -1):
                # We have a label
                for span in td.getchildren():
                    if (span.get("class").find("txt") != -1):
                        label = span.text

                # If we did find a label we have to look 
                # for a value 
                if (label and len(label) > 0):
                    next_td = all_tds[td_index + 1]

                    if (next_td.get("class").find("data") != -1):
                        # We have a data
                        for span in next_td.getchildren():
                            if (span.get("class").find("txt") != -1):
                                if (span.text):
                                    data = span.text
                                else:
                                    # If it is a link
                                    span_children = span.getchildren()
                                    if (span_children and len(span_children) > 0):
                                        data = span_children[0].text

                                # Include into dict
                                all_data[label] = data

                                # Erase it
                                label = ""
                                data = ""

    return all_data



def send_email(message):
    try:
        sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
        response = sg.send(message)
        print(response.status_code)
    except Exception as e:
        print("Deu erro na hora de enviar o email", str(e))
    


try: 
    if __name__ == '__main__':
        from waitingbar import WaitingBar
        
        THE_BAR = WaitingBar('[*] Downloading...')

        lista = get_data()
        THE_BAR.stop()
        # print("Get all stocks data")


        #Transform em uma lista, agora preciso passar para formato JSON
        array_format = list(lista.items())

        # print(array_format, len(array_format))

        hashes_list = []
        # First include the list of all hashes
        for i in range(0, len(array_format)):
            hashes_list.append(array_format[i][1])

        stocks = []
        # Then from a list of hashes we will transform to a list of stocks
        for i in range(0, len(hashes_list)):
            for key in hashes_list[i]:
                # Adds stockCode
                hashes_list[i][key]["stockCode"] = key
                stocks.append(hashes_list[i][key])
        


    #     json_format = {
    #     "0": {
    #         "DAGB33": {
    #             "Cresc.5a": "46,43%",
    #             "DY": "0,00%",
    #             "Div.Brut/Pat.": "1,37",
    #             "EBITDA": "4,75%",
    #             "EV/EBIT": "0,00",
    #             "Liq.2m.": "916.730,00",
    #             "Liq.Corr.": "1,16",
    #             "Mrg.Liq.": "0,38%",
    #             "P/Ativ.Circ.Liq.": "0,00",
    #             "P/Ativo": "0,000",
    #             "P/Cap.Giro": "0,00",
    #             "P/EBIT": "0,00",
    #             "P/L": "0,00",
    #             "P/VP": "0,00",
    #             "PSR": "0,000",
    #             "Pat.Liq": "9.803.230.000,00",
    #             "ROE": "-0,47%",
    #             "ROIC": "4,59%",
    #             "cotacao": "480,00",
    #             "nota": 0.5
    #         }
    #     }
    # }

        # Calculate the score of the stock
        final_stocks = []
        for stock in stocks:
            nota = 0
            patrLiq = float(stock["Pat.Liq"].replace('.', '').replace(',', '.'))
            if patrLiq > 2000000000:
                nota = nota + 1
            liqCorr = float(stock["Liq.Corr."].replace('.', '').replace(',', '.').replace('%', ''))
            if liqCorr > 1.5:
                nota = nota + 1
            roe = float(stock["ROE"].replace('.', '').replace(',', '.').replace('%', ''))
            if roe > 20: 
                nota = nota + 1
            divPat = float(stock["Div.Brut/Pat."].replace('.', '').replace(',', '.').replace('%', ''))
            if divPat < 0.5 and divPat > 0: 
                nota = nota + 1
            cresc = float(stock["Cresc.5a"].replace('.', '').replace(',', '.').replace('%', ''))
            if cresc > 5: 
                nota = nota + 1
            pvp = float(stock["P/VP"].replace('.', '').replace(',', '.').replace('%', ''))
            if pvp < 2 and pvp > 0: 
                nota = nota + 1
            pl = float(stock["P/L"].replace('.', '').replace(',', '.').replace('%', ''))
            if pl < 15 and pl > 0: 
                nota = nota + 1
            dy = float(stock["DY"].replace('.', '').replace(',', '.').replace('%', ''))
            if dy > 2.5: 
                nota = nota + 1
            stock["nota"] = float(nota) / 8.0 * 10.0

            newStock = {}
            newStock["stockCode"] = stock["stockCode"]
            newStock["patrimonioLiquido"] = patrLiq
            newStock["liquidezCorrente"] = liqCorr
            newStock["ROE"] = roe
            newStock["divSobrePatrimonio"] = divPat
            newStock["crescimentoCincoAnos"] = cresc
            newStock["precoSobreVP"] = pvp
            newStock["precoSobreLucro"] = pl
            newStock["dividendos"] = dy
            newStock["score"] = stock["nota"]
            newStock["stockPrice"] = float(stock["cotacao"].replace('.', '').replace(',', '.'))
            newStock["PSR"] = float(stock["PSR"].replace('.', '').replace(',', '.'))
            newStock["precoSobreAtivo"] = float(stock['P/Ativo'].replace('.', '').replace(',', '.'))
            newStock["precoSobreCapitalGiro"] = float(stock['P/Cap.Giro'].replace('.', '').replace(',', '.'))
            newStock["precoSobreEBIT"] = float(stock['P/EBIT'].replace('.', '').replace(',', '.'))
            newStock["precoSobreAtivoCirculante"] = float(stock['P/Ativ.Circ.Liq.'].replace('.', '').replace(',', '.'))
            newStock["EVSobreEBIT"] = float(stock['EV/EBIT'].replace('.', '').replace(',', '.'))
            newStock["margemEBIT"] = float(stock["EBITDA"].replace('.', '').replace(',', '.').replace('%', ''))
            newStock["margemLiquida"] = float(stock['Mrg.Liq.'].replace('.', '').replace(',', '.').replace('%', ''))
            newStock["ROIC"] = float(stock["ROIC"].replace('.', '').replace(',', '.').replace('%', ''))
            newStock["liquidezDoisMeses"] = float(stock['Liq.2m.'].replace('.', '').replace(',', '.').replace('%', ''))
            newStock["timestamp"] = datetime.datetime.now()

            # Get more information
            print("Getting more information from stock ", newStock["stockCode"])
            specific_data = get_specific_data(newStock["stockCode"])


            # Add everything to the object
            newStock["tipo"] = specific_data['Tipo']
            newStock["name"] = specific_data['Empresa']
            newStock["setor"] = specific_data['Setor']
            newStock["subsetor"] = specific_data['Subsetor']
            newStock["max52sem"] = float(specific_data['Max 52 sem'].replace('.', '').replace(',', '.')) if 'Max 52 sem' in specific_data and not "-" in specific_data['Max 52 sem'] else 0
            newStock["volMed2M"] = float(specific_data['Vol $ méd (2m)'].replace('.', '').replace(',', '.')) if 'Vol $ méd (2m)' in specific_data and not "-" in specific_data['Vol $ méd (2m)'] else 0
            newStock["valorMercado"] = float(specific_data['Valor de mercado'].replace('.', '').replace(',', '.')) if 'Valor de mercado' in specific_data and not "-" in specific_data['Valor de mercado'] else 0
            newStock["valorFirma"] = float(specific_data['Valor da firma'].replace('.', '').replace(',', '.')) if 'Valor da firma' in specific_data and not "-" in specific_data['Valor da firma'] else 0
            newStock["nAcoes"] = float(specific_data['Nro. Ações'].replace('.', '').replace(',', '.')) if 'Nro. Ações' in specific_data and not "-" in specific_data['Nro. Ações'] else 0
            newStock["lucroPorAcao"] = float(specific_data['LPA'].replace('.', '').replace(',', '.')) if 'LPA' in specific_data and not "-" in specific_data['LPA'] else 0
            newStock["margemBruta"] = float(specific_data['Marg. Bruta'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Marg. Bruta' in specific_data and not "-" in specific_data['Marg. Bruta'] else 0
            newStock["EBITsobreAtivo"] = float(specific_data['EBIT / Ativo'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'EBIT / Ativo' in specific_data and not "-" in specific_data['EBIT / Ativo'] else 0
            newStock["giroAtivos"] = float(specific_data['Giro Ativos'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Giro Ativos' in specific_data and not "-" in specific_data['Giro Ativos'] else 0
            newStock["ativo"] = float(specific_data['Ativo'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Ativo' in specific_data and not "-" in specific_data['Ativo'] else 0
            newStock["divBruta"] = float(specific_data['Dív. Bruta'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Dív. Bruta' in specific_data and not "-" in specific_data['Dív. Bruta'] else 0
            newStock["divLiquida"] = float(specific_data['Dív. Líquida'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Dív. Líquida' in specific_data and not "-" in specific_data['Dív. Líquida'] else 0
            newStock["disponibilidades"] = float(specific_data['Disponibilidades'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Disponibilidades' in specific_data and not "-" in specific_data['Disponibilidades'] else 0
            newStock["receitaLiquida"] = float(specific_data['Receita Líquida'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Receita Líquida' in specific_data and not "-" in specific_data['Receita Líquida'] else 0
            newStock["lucroLiquido"] = float(specific_data['Lucro Líquido'].replace('.', '').replace(',', '.').replace('%', '').replace("\n", "")) if 'Lucro Líquido' in specific_data and not "-" in specific_data['Lucro Líquido'] else 0

            
            final_stocks.append(newStock)



        # Saves in mongoDB
        client = MongoClient(os.environ['MONGO_URI'])

        print("Peguei todos os stocks, agora preciso salvar")


        recent_stocks_db = client.recentStocks
        all_stocks_coll = recent_stocks_db.stocks

        # First drop the collection
        recent_stocks_db.stocks.drop()

        for i in range(0, len(final_stocks)):
            stock = final_stocks[i]
            # Insert in mongo
            stock_id = all_stocks_coll.insert_one(stock).inserted_id
            print("Inserted object on recent Objects ", i + 1, " of ", len(final_stocks), " :",   stock_id)


        # Send email of success
        message = Mail(from_email='danilo_aleixo@hotmail.com', to_emails=os.environ.get('EMAIL_TO'), subject='Cron de analise diária, rodou certinho', html_content='Deu certo')
        send_email(message)

except Exception as e:
    print("Deu erro", str(e))
    # Send email of error
    message = Mail(from_email='danilo_aleixo@hotmail.com', to_emails=os.environ.get('EMAIL_TO'), subject='ERROR: Cron de analise diária, deu merda', html_content='Deu errado em ' + str(e))
    send_email(message)





================================================
FILE: gettingstarted/__init__.py
================================================


================================================
FILE: gettingstarted/settings.py
================================================
"""
Django settings for gettingstarted project.

Generated by 'django-admin startproject' using Django 2.0.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import os
import django_heroku


# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'CHANGE_ME!!!! (P.S. the SECRET_KEY environment variable will be used, if set, instead).'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hello'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'gettingstarted.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'gettingstarted.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'

django_heroku.settings(locals())

================================================
FILE: gettingstarted/static/humans.txt
================================================


================================================
FILE: gettingstarted/urls.py
================================================
from django.conf.urls import include, url
from django.urls import path

from django.contrib import admin
admin.autodiscover()

import hello.views

# Examples:
# url(r'^$', 'gettingstarted.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),

urlpatterns = [
    url(r'^$', hello.views.index, name='index'),
    url(r'^db', hello.views.db, name='db'),
    path('admin/', admin.site.urls),
]


================================================
FILE: gettingstarted/wsgi.py
================================================
"""
WSGI config for gettingstarted project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
"""

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings")

from django.core.wsgi import get_wsgi_application

application = get_wsgi_application()


================================================
FILE: hello/__init__.py
================================================


================================================
FILE: hello/admin.py
================================================
from django.contrib import admin

# Register your models here.


================================================
FILE: hello/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-01-27 21:54
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Greeting',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('when', models.DateTimeField(auto_now_add=True, verbose_name=b'date created')),
            ],
        ),
    ]


================================================
FILE: hello/migrations/__init__.py
================================================


================================================
FILE: hello/models.py
================================================
from django.db import models

# Create your models here.
class Greeting(models.Model):
    when = models.DateTimeField('date created', auto_now_add=True)


================================================
FILE: hello/templates/base.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>Python Getting Started on Heroku</title>
  <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
  <style type="text/css">
    .jumbotron {
        background: #532f8c;
        color: white;
        padding-bottom: 80px
    }
    .jumbotron .btn-primary {
        background: #845ac7;
        border-color: #845ac7
    }
    .jumbotron .btn-primary:hover {
        background: #7646c1
    }
    .jumbotron p {
        color: #d9ccee;
        max-width: 75%;
        margin: 1em auto 2em
    }
    .navbar+.jumbotron {
        margin-top: -20px
    }
    .jumbotron .lang-logo {
        display: block;
        background: #b01302;
        border-radius: 50%;
        overflow: hidden;
        width: 100px;
        height: 100px;
        margin: auto;
        border: 2px solid white
    }
    .jumbotron .lang-logo img {
        max-width: 100%
    }


  </style>
</head>
<body>
<nav class="navbar navbar-default navbar-static-top navbar-inverse">
  <div class="container">
    <ul class="nav navbar-nav">
      <li class="active">
        <a href="/"><span class="glyphicon glyphicon-home"></span> Home</a>
      </li>
      <li>
        <a href="https://devcenter.heroku.com/articles/how-heroku-works"><span class="glyphicon glyphicon-user"></span> How Heroku Works</a>
      </li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-info-sign"></span> Getting Started Guides <span class="caret"></span></a>
          <ul class="dropdown-menu" role="menu">
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-ruby">Getting Started with Ruby on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Getting Started with Node on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-php">Getting Started with PHP on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started with Python on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-java">Getting Started with Java on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-clojure">Getting Started with Clojure on Heroku</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-scala">Getting Started with Scala on Heroku</a></li>
            <li class="divider"></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-heroku-and-connect-without-local-dev">Getting Started on Heroku with Heroku Connect</a></li>
            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-jruby">Getting Started with Ruby on Heroku (Microsoft Windows)</a></li>
          </ul>
      </li>
    </ul>
    <ul class="nav navbar-nav navbar-right">
      <li class="navbar-right">
        <a href="https://devcenter.heroku.com"><span class="glyphicon glyphicon-book"></span> Heroku Dev Center</a>
      </li>
    </ul>
  </div>
</nav>

{% block content %}{% endblock %}

</body>
</html>


================================================
FILE: hello/templates/db.html
================================================
{% extends "base.html" %}
{% load staticfiles %}

{% block content %}
  <div class="container">


<h2>Page View Report</h2>


<ul>

{% for greeting in greetings %}
    <li>{{ greeting.when }}</li>
{% endfor %}

</ul>

</div>

{% endblock %}

================================================
FILE: hello/templates/index.html
================================================
{% extends "base.html" %}
{% load staticfiles %}

{% block content %}

<div class="jumbotron text-center">
  <div class="container">
    <a href="/" class="lang-logo">
      <img src="{% static 'lang-logo.png'%}">
    </a>
    <h1>Getting Started with Python on Heroku</h1>
    <p>This is a sample Python application deployed to Heroku. It's a reasonably simple app - but a good foundation for understanding how to get the most out of the Heroku platform.</p>
    <a type="button" class="btn btn-lg btn-default" href="https://devcenter.heroku.com/articles/getting-started-with-python"><span class="glyphicon glyphicon-flash"></span> Getting Started with Python</a>
    <a type="button" class="btn btn-lg btn-primary" href="https://github.com/heroku/python-getting-started"><span class="glyphicon glyphicon-download"></span> Source on GitHub</a>
  </div>
</div>
<div class="container">
  <div class="alert alert-info text-center" role="alert">
    To deploy your own copy, and learn the fundamentals of the Heroku platform, head over to the <a href="https://devcenter.heroku.com/articles/getting-started-with-python" class="alert-link">Getting Started with Python on Heroku</a> tutorial.
  </div>
  <hr>
  <div class="row">
    <div class="col-md-6">
      <h3><span class="glyphicon glyphicon-info-sign"></span> How this sample app works</h3>
      <ul>
        <li>This app was deployed to Heroku, either using Git or by using <a href="https://github.com/heroku/python-getting-started">Heroku Button</a> on the repository.</li>

        <li>When Heroku received the source code, it fetched all the dependencies in the <a href="https://github.com/heroku/python-getting-started/blob/master/Pipfile">Pipfile</a>, creating a deployable slug.</li>
        <li>The platform then spins up a dyno, a lightweight container that provides an isolated environment in which the slug can be mounted and executed.</li>
        <li>You can scale your app, manage it, and deploy over <a href="https://addons.heroku.com/">150 add-on services</a>, from the Dashboard or CLI.</li>
      </ul>
    </div>
    <div class="col-md-6">
      <h3><span class="glyphicon glyphicon-link"></span> Next Steps</h3>
      <ul>
        <li>If you are following the <a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started</a> guide, then please head back to the tutorial and follow the next steps!</li>
        <li>If you deployed this app by deploying the Heroku Button, then in a command line shell, run:</li>
        <ul>
          <li><code>git clone https://github.com/heroku/python-getting-started.git</code> - this will create a local copy of the source code for the app</li>
          <li><code>cd python-getting-started</code> - change directory into the local source code repository</li>
          <li><code>heroku git:remote -a &lt;your-app-name></code> - associate the Heroku app with the repository</li>
          <li>You'll now be set up to run the app locally, or <a href="https://devcenter.heroku.com/articles/getting-started-with-python#push-local-changes">deploy changes</a> to Heroku</li>
        </ul>
      </ul>
      <h3><span class="glyphicon glyphicon-link"></span> Helpful Links</h3>
      <ul>
        <li><a href="https://www.heroku.com/home">Heroku</a></li>
        <li><a href="https://devcenter.heroku.com/">Heroku Dev Center</a></li>
        <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started with Python on Heroku</a></li>
        <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Configuring Django Apps for Heroku</a></li>
      </ul>
    </div>
  </div> <!-- row -->
   <div class="alert alert-info text-center" role="alert">
    Please do work through the Getting Started guide, even if you do know how to build such an application.  The guide covers the basics of working with Heroku, and will familiarize you with all the concepts you need in order to build and deploy your own apps.
  </div>
</div>
{% endblock %}


================================================
FILE: hello/tests.py
================================================
from django.contrib.auth.models import AnonymousUser, User
from django.test import TestCase, RequestFactory

from .views import index

class SimpleTest(TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()

    def test_details(self):
        # Create an instance of a GET request.
        request = self.factory.get('/')
        request.user = AnonymousUser()

        # Test my_view() as if it were deployed at /customer/details
        response = index(request)
        self.assertEqual(response.status_code, 200)

================================================
FILE: hello/views.py
================================================
from django.shortcuts import render
from django.http import HttpResponse

from .models import Greeting

# Create your views here.
def index(request):
    # return HttpResponse('Hello from Python!')
    return render(request, 'index.html')


def db(request):

    greeting = Greeting()
    greeting.save()

    greetings = Greeting.objects.all()

    return render(request, 'db.html', {'greetings': greetings})



================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html class="no-js" lang="en">



<head>
		<meta http-equiv="refresh" content="0; url=https://bovespastockratings.firebaseapp.com" />
</head>
</html>


================================================
FILE: manage.py
================================================
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)


================================================
FILE: requirements.txt
================================================
asn1crypto==0.24.0
certifi==2019.9.11
cffi==1.12.3
chardet==3.0.4
crypto==1.4.1
cryptography==3.3.2
dnspython==1.16.0
gcloud==0.18.3
googleapis-common-protos==1.6.0
httplib2==0.19.0
idna==2.8
jwcrypto==0.6.0
lxml==4.6.3
Naked==0.1.31
oauth2client==4.1.3
protobuf==3.10.0rc1
pyasn1==0.4.7
pyasn1-modules==0.2.6
pycparser==2.19
pycryptodome==3.6.6
pymongo==3.9.0
python-jwt==3.2.4
PyYAML==5.4
requests==2.22.0
requests-toolbelt==0.9.1
rsa==4.7
shellescape==3.4.1
six==1.12.0
sseclient==0.0.24
urllib3==1.26.5
sendgrid==6.1.1


================================================
FILE: services.sh
================================================
#!/bin/bash
docker-compose -f docker-compose.yml up -d

================================================
FILE: waitingbar.py
================================================
#!/usr/bin/env python3

import sys
import threading
import time

from itertools import cycle


class WaitingBar(object):
    '''
    This class prints a fancy waiting bar with Greek chars and spins.
    It uses a thread to keep printing the bar while the main program runs

    Usage:

    THE_BAR = WaitingBar('Your Message Here')
    # Do something slow here
    (...)
    THE_BAR.stop()
    
    copyright phoemur - 2016
    '''

    def __init__(self, message='[*] Wait until loading is complete...'):
        self.MESSAGE = ' ' + str(message)
        self.CYCLES = ['-', '-', '\\', '\\', '|', '|', '/', '/', '-', '-', '\\', '\\', '|', '|', '/', '/']
        self.intab = u'abcdefghijklmnopqrstuvwxyzáàãâéèẽêíìîĩóòôõúùũûçABCDEFGHIJKLMNOPQRSTUVWXYZÁÀÃÂÉÈẼÊÍÌÎĨÓÒÔÕÚÙŨÛÇ'
        self.outab = u'αβ¢ΔεϝγηιφκλμνΩπσϼΣτυϞωχψζααααεεεειιιιΩΩΩΩυυυυ¢αβ¢ΔεϝγηιφκλμνΩπσϼΣτυϞωχψζααααεεεειιιιΩΩΩΩυυυυ¢'
        self.TABLE = {x: y for x, y in zip(self.intab, self.outab)}

        self.event = threading.Event()
        self.waiting_bar = threading.Thread(target=self.start, args=(self.event,))
        self.waiting_bar.start()

    def start(self, e):
        for index in cycle(range(len(self.MESSAGE))):
            if e.is_set():
                break
            if not self.MESSAGE[index].isalpha():
                continue
            for c in self.CYCLES:
                buff = list(self.MESSAGE)
                buff.append(c)

                try:
                    if sys.stdout.encoding.upper() == 'UTF-8':
                        buff[index] = self.TABLE[buff[index]]
                    else:
                        buff[index] = buff[index].swapcase()
                except KeyError:
                    pass

                sys.stdout.write(''.join(buff))
                time.sleep(0.05)
                sys.stdout.write('\r')
                sys.stdout.flush()

    def stop(self):
        self.event.set()
        self.waiting_bar.join()
        sys.stdout.write(self.MESSAGE + ' \n')


if __name__ == '__main__':
    '''
    A simple example to demonstrate the class in action
    '''

    # Start the bar
    THE_BAR = WaitingBar('[*] Calculating useless stuff...')

    # Do something slow
    import math
    from pprint import pprint

    a_list = {a: b for a, b in zip(range(1, 41), map(math.factorial, range(1, 41)))}
    time.sleep(20)

    # Stop the bar and print result
    THE_BAR.stop()
    pprint(a_list)
Download .txt
gitextract_nx7a1d76/

├── .gitignore
├── .gitmodules
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Pipfile
├── Procfile
├── Procfile.windows
├── README.md
├── app.json
├── client/
│   ├── getFromFirebase.js
│   └── styles.css
├── docker-compose.yml
├── functions/
│   ├── .gitignore
│   ├── package.json
│   ├── src/
│   │   └── index.ts
│   ├── tsconfig.json
│   └── tslint.json
├── fundamentus.py
├── gettingstarted/
│   ├── __init__.py
│   ├── settings.py
│   ├── static/
│   │   └── humans.txt
│   ├── urls.py
│   └── wsgi.py
├── hello/
│   ├── __init__.py
│   ├── admin.py
│   ├── migrations/
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── db.html
│   │   └── index.html
│   ├── tests.py
│   └── views.py
├── index.html
├── manage.py
├── requirements.txt
├── services.sh
└── waitingbar.py
Download .txt
SYMBOL INDEX (17 symbols across 8 files)

FILE: client/getFromFirebase.js
  function initInputs (line 255) | function initInputs(){

FILE: functions/src/index.ts
  function query (line 65) | async function query<T>(conn: Mysql.Connection, queryString: string, sub...
  function transformIntoMySQLString (line 82) | function transformIntoMySQLString(queryString: string, substituionValues...

FILE: fundamentus.py
  function get_data (line 21) | def get_data(*args, **kwargs):
  function get_specific_data (line 112) | def get_specific_data(stock):
  function send_email (line 186) | def send_email(message):

FILE: hello/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: hello/models.py
  class Greeting (line 4) | class Greeting(models.Model):

FILE: hello/tests.py
  class SimpleTest (line 6) | class SimpleTest(TestCase):
    method setUp (line 7) | def setUp(self):
    method test_details (line 11) | def test_details(self):

FILE: hello/views.py
  function index (line 7) | def index(request):
  function db (line 12) | def db(request):

FILE: waitingbar.py
  class WaitingBar (line 10) | class WaitingBar(object):
    method __init__ (line 25) | def __init__(self, message='[*] Wait until loading is complete...'):
    method start (line 36) | def start(self, e):
    method stop (line 59) | def stop(self):
Condensed preview — 40 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (76K chars).
[
  {
    "path": ".gitignore",
    "chars": 67,
    "preview": "__pycache__/*\nscripts/__pycache__/*\nfirebase.json\n.env\nPipfile.lock"
  },
  {
    "path": ".gitmodules",
    "chars": 404,
    "preview": "[submodule \"fundamentalAnalysisHistoricalDataClient\"]\n\tpath = fundamentalAnalysisHistoricalDataClient\n\turl = https://git"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3222,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4217,
    "preview": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail,"
  },
  {
    "path": "Dockerfile",
    "chars": 577,
    "preview": "FROM python\n\n\nCOPY fundamentus.py /data/fundamentus.py\nCOPY waitingbar.py /data/waitingbar.py\nWORKDIR /data\n\n# RUN pip i"
  },
  {
    "path": "LICENSE",
    "chars": 1074,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 phoemur\n\nPermission is hereby granted, free of charge, to any person obtaining"
  },
  {
    "path": "Pipfile",
    "chars": 168,
    "preview": "[[source]]\n\nurl = \"https://pypi.python.org/simple\"\nverify_ssl = true\n\n\n[packages]\n\ndjango = \"*\"\ngunicorn = \"*\"\ndjango-he"
  },
  {
    "path": "Procfile",
    "chars": 34,
    "preview": "web: gunicorn gettingstarted.wsgi\n"
  },
  {
    "path": "Procfile.windows",
    "chars": 45,
    "preview": "web: python manage.py runserver 0.0.0.0:5000\n"
  },
  {
    "path": "README.md",
    "chars": 3129,
    "preview": "# Bovespa Stock Ratings\n\nProjeto de análise de dados fundamentalistas da Bovespa\n\n**If you like this project you can sup"
  },
  {
    "path": "app.json",
    "chars": 609,
    "preview": "{\n  \"name\": \"Start on Heroku: Python\",\n  \"description\": \"A barebones Python app, which can easily be deployed to Heroku."
  },
  {
    "path": "client/getFromFirebase.js",
    "chars": 10357,
    "preview": "// \n// Get info from frebase and show it on the datatable\n// \n\n\n\nvar database = firebase.database();\nvar arrayStocksHist"
  },
  {
    "path": "client/styles.css",
    "chars": 1013,
    "preview": "@keyframes App-logo-spin {\n  from { transform: rotate(0deg); }\n  to { transform: rotate(360deg); }\n}\n\nth {\n  background:"
  },
  {
    "path": "docker-compose.yml",
    "chars": 306,
    "preview": "version: \"3.4\"\nservices:\n  mongo:\n    network_mode: host\n    image: willguitaradmfar/mongo-auth\n    environment:\n      C"
  },
  {
    "path": "functions/.gitignore",
    "chars": 107,
    "preview": "## Compiled JavaScript files\n**/*.js\n**/*.js.map\n\n# Typescript v1 declaration files\ntypings/\n\nnode_modules/"
  },
  {
    "path": "functions/package.json",
    "chars": 659,
    "preview": "{\n  \"name\": \"functions\",\n  \"scripts\": {\n    \"lint\": \"tslint --project tsconfig.json\",\n    \"build\": \"tsc\",\n    \"serve\": \""
  },
  {
    "path": "functions/src/index.ts",
    "chars": 5123,
    "preview": "import { Change } from 'firebase-functions';\nimport { DataSnapshot } from 'firebase-functions/lib/providers/database';\ni"
  },
  {
    "path": "functions/tsconfig.json",
    "chars": 258,
    "preview": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"outDi"
  },
  {
    "path": "functions/tslint.json",
    "chars": 5045,
    "preview": "{\n  \"rules\": {\n    // -- Strict errors --\n    // These lint rules are likely always a good idea.\n\n    // Force function "
  },
  {
    "path": "fundamentus.py",
    "chars": 16627,
    "preview": "#!/usr/bin/env python3\n\nimport re\nimport urllib.request\nimport urllib.parse\nimport http.cookiejar\nimport time\nimport lxm"
  },
  {
    "path": "gettingstarted/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gettingstarted/settings.py",
    "chars": 3214,
    "preview": "\"\"\"\nDjango settings for gettingstarted project.\n\nGenerated by 'django-admin startproject' using Django 2.0.\n\nFor more in"
  },
  {
    "path": "gettingstarted/static/humans.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gettingstarted/urls.py",
    "chars": 404,
    "preview": "from django.conf.urls import include, url\nfrom django.urls import path\n\nfrom django.contrib import admin\nadmin.autodisco"
  },
  {
    "path": "gettingstarted/wsgi.py",
    "chars": 404,
    "preview": "\"\"\"\nWSGI config for gettingstarted project.\n\nIt exposes the WSGI callable as a module-level variable named ``application"
  },
  {
    "path": "hello/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "hello/admin.py",
    "chars": 63,
    "preview": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "hello/migrations/0001_initial.py",
    "chars": 589,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.1 on 2016-01-27 21:54\nfrom __future__ import unicode_literals\n\nfrom dj"
  },
  {
    "path": "hello/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "hello/models.py",
    "chars": 154,
    "preview": "from django.db import models\n\n# Create your models here.\nclass Greeting(models.Model):\n    when = models.DateTimeField('"
  },
  {
    "path": "hello/templates/base.html",
    "chars": 3519,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n<title>Python Getting Started on Heroku</title>\n  <link rel=\"stylesheet\" type=\"text/css\" h"
  },
  {
    "path": "hello/templates/db.html",
    "chars": 240,
    "preview": "{% extends \"base.html\" %}\n{% load staticfiles %}\n\n{% block content %}\n  <div class=\"container\">\n\n\n<h2>Page View Report</"
  },
  {
    "path": "hello/templates/index.html",
    "chars": 4029,
    "preview": "{% extends \"base.html\" %}\n{% load staticfiles %}\n\n{% block content %}\n\n<div class=\"jumbotron text-center\">\n  <div class="
  },
  {
    "path": "hello/tests.py",
    "chars": 592,
    "preview": "from django.contrib.auth.models import AnonymousUser, User\nfrom django.test import TestCase, RequestFactory\n\nfrom .views"
  },
  {
    "path": "hello/views.py",
    "chars": 411,
    "preview": "from django.shortcuts import render\nfrom django.http import HttpResponse\n\nfrom .models import Greeting\n\n# Create your vi"
  },
  {
    "path": "index.html",
    "chars": 166,
    "preview": "<!DOCTYPE html>\n<html class=\"no-js\" lang=\"en\">\n\n\n\n<head>\n\t\t<meta http-equiv=\"refresh\" content=\"0; url=https://bovespasto"
  },
  {
    "path": "manage.py",
    "chars": 257,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
  },
  {
    "path": "requirements.txt",
    "chars": 523,
    "preview": "asn1crypto==0.24.0\ncertifi==2019.9.11\ncffi==1.12.3\nchardet==3.0.4\ncrypto==1.4.1\ncryptography==3.3.2\ndnspython==1.16.0\ngc"
  },
  {
    "path": "services.sh",
    "chars": 54,
    "preview": "#!/bin/bash\ndocker-compose -f docker-compose.yml up -d"
  },
  {
    "path": "waitingbar.py",
    "chars": 2434,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport threading\nimport time\n\nfrom itertools import cycle\n\n\nclass WaitingBar(object):"
  }
]

About this extraction

This page contains the full source code of the daniloaleixo/bovespaStockRatings GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 40 files (68.5 KB), approximately 18.9k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!