Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b77410e
Ajout ListWidget pour Articles
Vincannes Mar 18, 2021
9474b72
Ajout Articles par ticker + Article Page d'Acceuil + Table Finances
Vincannes Mar 19, 2021
6cefc99
Modification ArticlesItem + MACD inversé
Vincannes Mar 21, 2021
5fb0ada
add feature markets evolution days in Welcome page
Vincannes Mar 24, 2021
73134db
Merge branch 'master' of https://github.com/AlexLaur/TradeHelper into…
Vincannes Mar 24, 2021
fd6f2dd
Conflits resolus
Vincannes Mar 24, 2021
dab1b6f
Add Financial Table + Hover Selection row in Table
Vincannes Mar 26, 2021
3305526
Forget reactive articles + ReadMe
Vincannes Mar 26, 2021
9628c1f
Refining Market info in Welcome Page
Vincannes Mar 26, 2021
6e6c74a
Modif css Indicator Setting for Windows
Vincannes Mar 27, 2021
cf5011b
Add Close Price Line and Legend in Y Axis
Vincannes Mar 28, 2021
ca65705
add args for toolbars actions
AlexLaur Mar 28, 2021
ae5a8e3
args for draw line
AlexLaur Mar 28, 2021
274712d
edit events for action trigerred
AlexLaur Mar 28, 2021
57e7a7f
edit signal action triggered
AlexLaur Mar 28, 2021
274d84a
Base for drawing ROI
AlexLaur Mar 28, 2021
4f99c70
continue tests arround rois
AlexLaur Mar 29, 2021
fe45250
Fibonnaci fonctionnel but need a refacto
Vincannes Apr 2, 2021
e2c70bd
Add sentimentals in Welcome Page + In TableFinancial
Vincannes Apr 4, 2021
6ce106f
Add sentimentals in Welcome Page + In TableFinancial
Vincannes Apr 4, 2021
25d2ad3
Refine Articles
Vincannes Apr 4, 2021
098c9a9
delete function in view
Vincannes Apr 4, 2021
f9d1d8b
Refine thumbnail articles
Vincannes Apr 4, 2021
ac8f6fb
Add Splashscreen
Vincannes Apr 4, 2021
b118e0b
Change market widget, was nan during weekend
Vincannes Apr 5, 2021
12f35d5
change css slide bar SentimentalWidget
Vincannes Apr 5, 2021
cca89bd
Change Financials Score in table + SplashScreen Image + 2 predictions…
Vincannes Apr 5, 2021
cdfb7e0
Change Financials Score in table + SplashScreen Image + 2 predictions…
Vincannes Apr 5, 2021
45acad2
Merge remote-tracking branch 'origin/roi-dev' into vinc_
Vincannes Apr 5, 2021
7eec5cb
Git Merge Branch ROI_Dev
Vincannes Apr 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
This aplication is a exercice working with Qt, PyQt arround the finance.
It is largely inspired by `TradingView` which is a wonderfull tool for finance analysis.

![Preview](./preview_home.png)

![Preview](./preview.jpg)

## Installation
Expand Down Expand Up @@ -44,4 +46,9 @@ It is largely inspired by `TradingView` which is a wonderfull tool for finance a
- [ ] Save users settings
- [ ] Embeded Python Console ?
- [ ] Draw over the graph
- [ ] Use Machine learning to determine patterns
- [ ] Use Machine learning to determine patterns
- [ ] Draw Fibonnaci on Chart => 50% done
- [ ] Make Virtual Portefolio
- [ ] Avaible Trading
- [ ] SplashScreen Loading
- [ ] Find Compagnies with differents stratgies (Buffet, Peter Lynch, Carl Icahn)
177 changes: 177 additions & 0 deletions app/add_ons/indicators/fibonnaci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import numpy as np
import pyqtgraph as pg

from utils.indicators_utils import Indicator, InputField, ChoiceField

RATIO = [78.6, 61.8, 50.0, 38.2, 23.6]
COLORS = {
78.6: (255, 56, 56),
61.8: (218, 255, 56),
50.0: (56, 255, 82),
38.2: (148, 56, 255),
23.6: (56, 95, 255),
}

class Fibonnaci(Indicator):
def __init__(self):
super(Fibonnaci, self).__init__()

self.name = "Fibonnaci"
self.description = "Fibonnaci"

# Define and register all customisable settings
# field_input = ChoiceField(
# "Input", choices=["Open", "Close", "High", "Low"], default="Close"
# )
# self.register_field(field_input)
# line1 = InputField(
# "Fibonnaci", color=(51, 153, 255), value=3, width=2
# )
# self.register_fields(line1)

def create_indicator(self, graph_view, *args, **kwargs):
super(Fibonnaci, self).create_indicator(self, graph_view)

# Get values
values = graph_view.values
self.quotation_plot = graph_view.g_quotation

self.roi = pg.RectROI([347, 113], [50, 60],
invertible=True,
pen=pg.mkPen(color=(255, 255, 255),
width=1,),
hoverPen=None,
)

self.roi.addTranslateHandle((0,0))
self.quotation_plot.addItem(self.roi)

self.set_fibonnaci_levels()
self.roi.sigRegionChanged.connect(self.move_items)

def move_items(self):
"""This method is call everytime the ROI is move.
"""
self.set_fibonnaci_levels()

def set_fibonnaci_levels(self):
try:
self.quotation_plot.removeItem(self.line_78)
self.quotation_plot.removeItem(self.label_78)
self.quotation_plot.removeItem(self.line_61)
self.quotation_plot.removeItem(self.label_61)
self.quotation_plot.removeItem(self.line_50)
self.quotation_plot.removeItem(self.label_50)
self.quotation_plot.removeItem(self.line_38)
self.quotation_plot.removeItem(self.label_38)
self.quotation_plot.removeItem(self.line_23)
self.quotation_plot.removeItem(self.label_23)
self.quotation_plot.removeItem(self.label_1)
self.quotation_plot.removeItem(self.label_100)
except:
pass

self.line_78 = self._set_fibonnaci_level(prc=78.6)
self.label_78 = self._set_label_level(prc=78.6)

self.line_61 = self._set_fibonnaci_level(prc=61.8)
self.label_61 = self._set_label_level(prc=61.8)

self.line_50 = self._set_fibonnaci_level(prc=50.0)
self.label_50 = self._set_label_level(prc=50.0)

self.line_38 = self._set_fibonnaci_level(prc=38.2)
self.label_38 = self._set_label_level(prc=38.2)

self.line_23 = self._set_fibonnaci_level(prc=23.6)
self.label_23 = self._set_label_level(prc=23.6)

self.label_100 = self._set_label_level(prc=100)
self.label_1 = self._set_label_level(prc=1)

self.quotation_plot.addItem(self.line_78)
self.quotation_plot.addItem(self.label_78)
self.quotation_plot.addItem(self.line_61)
self.quotation_plot.addItem(self.label_61)
self.quotation_plot.addItem(self.line_50)
self.quotation_plot.addItem(self.label_50)
self.quotation_plot.addItem(self.line_38)
self.quotation_plot.addItem(self.label_38)
self.quotation_plot.addItem(self.line_23)
self.quotation_plot.addItem(self.label_23)
self.quotation_plot.addItem(self.label_100)
self.quotation_plot.addItem(self.label_1)

def _set_fibonnaci_level(self, prc=50.0):
"""This method plot line for each retracement
:param widget: ROIWidget
:type widget: PQQt.GraphWidget
"""
color = COLORS[prc]
xpos, ypos = self.position_line(prc)

line = pg.LineSegmentROI(positions=(xpos, ypos),
pen=pg.mkPen(color, width=2),
movable=False,
rotatable=False,
resizable=False,
)
line.setSelected(False)
return line


def _set_label_level(self, prc=50.0):
"""This method plot label for each retracement
:param widget: TextItem
:type widget: PQQt.GraphWidget
"""
xpos, ypos = self.position_line(prc)

percentg_lb = "0.{}".format(int(prc))
label = pg.TextItem(text=' {} ({})'.format(percentg_lb, round(ypos[1], 2)),
anchor=(0, 0.5),
)

# Lock Label to the Right of ROI
if xpos[0] < ypos[0]:
position = ypos[0]
else:
position = xpos[0]

label.setPos(position, ypos[1])
return label

def position_line(self, prc=50.0):
"""This method return the graph position for the levels
"""
rtc = self._get_fibonnaci_level(prc)[0]
x_pos = [self.roi.pos()[0], rtc]
y_pos = [self.roi.pos()[0] + self.roi.size()[0], rtc]
return x_pos, y_pos


def _get_fibonnaci_level(self, prc):
"""This method calcul the retracement level calculating the difference
between the min/max of the ROI.
:param prc: Percentage to calculate
:type float:
"""
# position is lower-left ROI
# use x_min and y_min with width and height to find the position
# on the graph.
pos = self.roi.getState()['pos']
size = self.roi.getState()['size']

y_min = pos[1]
y_max = pos[1] + size[1]
variation = y_max - y_min

retracement = []
retrc = variation * (prc / 100)
value = y_min + retrc
retracement.append(value)

return retracement

def remove_indicator(self, graph_view, *args, **kwargs):
super(Fibonnaci, self).remove_indicator(graph_view)
27 changes: 15 additions & 12 deletions app/libs/analysies/analyse_financials.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pprint import pprint
from utils import utils as utl
from libs.yahoo_fin import stock_info as sf
from .analyse import AnalyseData
from libs.analysies.analyse import AnalyseData


class AnalyseFondamental(object):
Expand All @@ -34,12 +34,6 @@ def __init__(self, ticker):
self.year_atual = self.resultat_datas.keys()[0]
self.year_before = self.resultat_datas.keys()[1]

# pprint(self.resultat_datas)
# pprint(self.balance_datas)
# pprint(self.cash_flow_datas)
# pprint(self.per_datas)
# pprint(self.statistic_datas)

self.datas = {}
self.data_analyse = {}

Expand All @@ -50,6 +44,7 @@ def __init__(self, ticker):

self.analyse = AnalyseData(self.data_analyse)
self.extend_dict_data()
self.tes()

def set_var(self):
self.actions = None
Expand Down Expand Up @@ -202,7 +197,7 @@ def datas_dict(self):
self.datas["Capitaux Propre"] = utl.format_data(
self.total_capitaux_propre.values.tolist()
)
self.datas["Score"] = [self.total_score()]
self.datas["Score"] = ["", "", "", "", self.total_score()]

self.bna_years()
self.per_years()
Expand All @@ -213,6 +208,12 @@ def datas_dict(self):
self.roe_roa_ratio(roa=False)
self.roe_roa_ratio(roa=True)


def tes(self):
for key, value in self.datas.items():
if len(value) <= 4:
self.datas[key].append("")

def data_for_analyse(self):
self.data_analyse["Actifs Total"] = self.datas["Actifs Total"]
self.data_analyse["BNA"] = self.datas["BNA"]
Expand All @@ -222,7 +223,6 @@ def data_for_analyse(self):
"Capitaux Propre"
] = self.total_capitaux_propre.values.tolist()
self.data_analyse["Chiffre d'affaires"] = self.chiffre_affaire.tolist()
self.data_analyse["Dividendes"] = self.datas["Dividendes"]
self.data_analyse["EBITDA"] = self.ebitda.values.tolist()
self.data_analyse["PER"] = self.datas["PER"]
self.data_analyse["ROA"] = self.datas["ROA"]
Expand Down Expand Up @@ -294,7 +294,10 @@ def dividendes_ratio(self):
calcul_rend = round(calcul_rend, 2)
rendement.append("{}€".format(calcul_rend))

self.datas["Dividendes"] = dividendes
self.data_analyse["Dividendes"] = dividendes
self.datas["Dividendes"] = []
for i in dividendes:
self.datas["Dividendes"].append(" ".join(["{}€".format(str(x)) for x in i]))
self.datas["Dividendes Rendement"] = [
"{}%".format(i) for i in rendement
]
Expand Down Expand Up @@ -339,6 +342,6 @@ def extend_dict_data(self):

if __name__ == "__main__":
test = AnalyseFondamental("AAPL")
pprint(test.data_analyse)
pprint(test.analyse.__dict__)
pprint(test.datas)
# pprint(test.analyse.__dict__)
# testq = AnalyseFondamental("BN.PA")
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ def __init__(self, ticker=None):
self.get_url(ticker=ticker)

def get_url(self, ticker):
if "{}.PA".format(ticker) in sf.tickers_cac().keys():
if "{}".format(ticker) in sf.tickers_cac().keys():
url = "https://www.boursorama.com/cours/actualites/1rP{}/".format(
ticker
ticker.split('.')[0]
)
else:
url = "https://www.boursorama.com/cours/actualites/{}/".format(
ticker
)
print(url)
self.response = requests.get(url, headers=self.headers)
self.soup()

Expand All @@ -61,8 +62,8 @@ def soup(self):
self.articles.append(
{
"title": title,
"date": time,
"descritpion": descritpion,
"published": time,
"summary": descritpion,
"link": "https://www.boursorama.com{}".format(link),
}
)
Expand Down
86 changes: 86 additions & 0 deletions app/libs/articles/yahoo_articles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#
# This Class get all articles from selected ticker
# from the Yahoo website.

import requests
from bs4 import BeautifulSoup
from utils import utils
from pprint import pprint
from libs.yahoo_fin import news


class ArticlesYahoo(object):
def __init__(self):
super(ArticlesYahoo, self).__init__()

self.articles = None

def get_articles_from_compagny(self, ticker):
self.articles = news.get_yf_rss(ticker)
compagny = utils.get_compagny_name_from_tick(ticker=ticker)

if not self.articles:
return

for article in self.articles:
article['compagny'] = compagny
self.get_thumbnail_link(article)
article['summary'] = self.cup_long_text(article['summary'])

return self.articles

def get_home_articles(self):
self.articles = news.get_yf_home_rss()

if not self.articles:
return

for article in self.articles:
article['published'] = article['published'].replace('T', ' ')
article['summary'] = ""
try:
article['img'] = article['media_content'][0]['url']
except:
article['img'] = ""


return self.articles

def get_thumbnail_link(self, article):
"""
This method scrap the img url of the article from the website.
"""
header = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36",
}
link = article['link']
request = requests.get(link, headers=header)
soup = BeautifulSoup(request.text, "html.parser")

try:
img = soup.findAll('img', {"class": "caas-img"})
img = img[-1]['src']
except:
img = None
article['img'] = img

return article


def cup_long_text(self, value):
"""
This method cut long description.
return: list.
"""
len_chart = 180
if len(value) > len_chart:
value = "{}...".format(value[0:len_chart])
return value


if __name__ == '__main__':
tick = "MSFT"
x = ArticlesYahoo()
# articles = x.get_articles_from_compagny(tick)
articles = x.get_home_articles()
pprint(articles)
Loading