Files
ctp_blogr/cao_blogr/views/portfolio.py
2023-01-30 15:53:59 +01:00

359 lines
14 KiB
Python

from pyramid.view import (
view_config,
)
from pyramid.httpexceptions import HTTPFound
from ..services.portfolio import PFService
from ..forms import ActifForm, Actif2Form, AllocationForm, HistoForm
from ..models.portfolio import Actifs, Histo, Allocation
import datetime #<- will be used to set default dates on models
import yfinance as yf
import json
import html
@view_config(route_name='portfolio', renderer='../templates/portfolio/portfolio.jinja2', permission='view')
def portfolio(request):
logged_in = request.authenticated_userid
url = request.route_url('portfolio')
# lire les categories
items = PFService.get_allocation(request, '0')
# construire la liste pour donut
donut_cible=[]
donut_cible.append(('Allocation cible', 'Pourcent'))
donut_actuel=[]
donut_actuel.append(('Allocation actuelle', 'Pourcent'))
# calculer % total
total = 0
for item in items:
# construire la liste pour donut cible
d = (item.classe, item.pc_cible)
donut_cible.append(d)
# construire la liste pour donut actuel
d = (item.classe, int(item.pc_atteint * 10))
donut_actuel.append(d)
# totaliser les pourcentages
total += item.pc_cible
swr_rate = 3.5
if total != 100:
request.session.flash('Attention, le total de votre répartition cible dépasse 100% : ' + str(total), 'warning')
# lire les actifs
actifs = PFService.get_actifs(request, '0')
# MAJ du prtefeuille
if 'form.submitted' in request.params:
# lire le cours de EURUSD
ticker = yf.Ticker('EUR=X')
# maj des parités des devises
PFService.update_actif_devise(request, 'USD', ticker.info.get('regularMarketPrice'))
for item in actifs:
if item.Allocation.type == 'ACTION':
# lire le cours de l'action
ticker = yf.Ticker(item.Actifs.symbole)
# ticker delisted ?
if ticker.info == None:
price = 0
else:
price = ticker.info.get('regularMarketPrice')
# caluler son rendement
dividends = PFService.get_dividends(ticker)
PFService.update_actif_valeur(request, item.Actifs.symbole, price, dividends)
# time.sleep(1) # attendre 2 secondes
# update du portefeuille
PFService.update_portefeuille(request, logged_in)
# relire les actifs
actifs = PFService.get_actifs(request, '0')
request.session.flash('Le portefeuille est mis à jour avec succès.', 'success')
total_valeur = 0
total_pv = 0
total_rdt = 0
for item in actifs:
total_valeur += item.Actifs.valeur
total_pv += item.Actifs.plus_value
if total_valeur == 0:
total_pc_value = 0
else:
total_pc_value = total_pv / total_valeur * 100
total_rdt += item.Actifs.rendement
# lire l'historique
histos = PFService.get_histo(request,'0')
courbe_evoln=[]
courbe_evoln.append(('Date', 'Valeur part PF', 'Valeur part CARINVT:FP'))
for item in histos:
# construire la liste pour donut cible
d = (item.date.strftime('%d/%m/%Y'), int(item.val_part * 1000), int(item.val_part_ref * 1000))
courbe_evoln.append(d)
return {
'page_title': "Portefeuille",
'url': url,
'items': items,
'donut_cible': json.dumps(donut_cible),
'donut_actuel': json.dumps(donut_actuel),
'courbe_evoln': json.dumps(courbe_evoln),
'actifs': actifs,
'total_valeur': total_valeur,
'total_pv': total_pv,
'total_pc_value': total_pc_value,
'total_rdt': total_rdt,
'swr_rate' : swr_rate,
'swr_amount': float(total_valeur) * swr_rate / 100,
}
@view_config(route_name='histo_list', renderer='../templates/portfolio/histo_list.jinja2', permission='view')
def histo_list(request):
# lire l historique
items = PFService.get_histo(request, '-1')
return {
'page_title': 'Historique des parts',
'items': items,
}
@view_config(route_name='allocation_edit', renderer='../templates/portfolio/allocation_edit.jinja2', permission='view')
def allocation_edit(request):
no_cat = request.matchdict['no_cat']
url = request.route_url('allocation_edit', no_cat=no_cat)
if no_cat == '0':
# create a new allocation
entry = Allocation()
form = AllocationForm(request.POST, entry)
page_title = "Nouvelle allocation"
else:
# modify post
entry = PFService.get_allocation(request, no_cat)
if not entry:
request.session.flash(u"Allocation non trouvée : %s" % no_cat, 'warning')
return HTTPFound(location=request.route_url('portfolio'))
form = AllocationForm(request.POST, entry)
page_title = "Modifier Allocation : " + str(entry.no_cat)
if 'form.submitted' in request.params :
if no_cat == '0':
form.populate_obj(entry)
entry.pc_atteint = 0
entry.valeur = 0
request.dbsession.add(entry)
return HTTPFound(location=request.route_url('portfolio'))
else:
del form.no_cat # SECURITY: prevent overwriting of primary key
form.populate_obj(entry)
return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params:
PFService.delete_allocation(request, entry.no_cat)
request.session.flash("La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('portfolio'))
return {
'page_title': page_title,
'url': url,
'form': form,
'item': entry,
}
@view_config(route_name='histo_edit', renderer='../templates/portfolio/histo_edit.jinja2', permission='view')
def histo_edit(request):
no_id = request.matchdict['no_id']
url = request.route_url('histo_edit', no_id=no_id)
if no_id == '0':
# create a new tag
entry = Histo()
entry.date = datetime.datetime.now()
form = HistoForm(request.POST, entry)
page_title = "Nouveau Histo"
else:
# modify post
entry = PFService.get_histo(request, no_id)
if not entry:
request.session.flash(u"Histo non trouvé : %s" % no_id, 'warning')
return HTTPFound(location=request.route_url('histo_list'))
form = HistoForm(request.POST, entry)
page_title = "Modifier histo no " + str(entry.no_id)
if 'form.submitted' in request.params and form.validate():
if no_id == '0':
form.populate_obj(entry)
request.dbsession.add(entry)
return HTTPFound(location=request.route_url('histo_list'))
else:
del form.no_id # SECURITY: prevent overwriting of primary key
form.populate_obj(entry)
# lire le cours de l'indice de réfence : Carmignac Investissement A EUR Acc
ticker = yf.Ticker('0P00000FB2.F')
entry.cours_ref = ticker.info.get('regularMarketPrice')
return HTTPFound(location=request.route_url('histo_list'))
if 'form.deleted' in request.params:
PFService.delete_histo(request, entry.no_id)
request.session.flash("La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('histo_list'))
return {
'page_title': page_title,
'url': url,
'form': form,
'item': entry,
}
@view_config(route_name='actif_edit', renderer='../templates/portfolio/actif_edit.jinja2', permission='view')
def actif_edit(request):
no_id = request.matchdict['no_id']
url = request.route_url('actif_edit', no_id=no_id)
# get the list of classes
classes = PFService.get_allocation_byType(request, 'ACTION')
if no_id == '0':
# create a new allocation
entry = Actifs()
entry.pru = 0
entry.cours = 0
entry.pc_rdt = 0
entry.ter = 0
form = ActifForm(request.POST, entry)
form.classe.choices = [(row.classe, row.classe) for row in classes]
page_title = "Nouvel actif"
else:
# modify post
entry = PFService.get_actifs(request, no_id)
if not entry:
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
return HTTPFound(location=request.route_url('portfolio'))
form = ActifForm(request.POST, entry)
form.classe.choices = [(row.classe, row.classe) for row in classes]
page_title = "Modifier Actif : " + entry.symbole
if 'form.submitted' in request.params :
if no_id == '0':
form.populate_obj(entry)
# récupérer le cours du symbole de Yahoo finance
ticker = yf.Ticker(entry.symbole)
entry.cours = ticker.fast_info.last_price
entry.devise = ticker.info.get('currency')
entry.libelle = html.unescape(ticker.info.get('shortName'))
# raccourcir le libelle
entry.libelle = entry.libelle.replace('UCITS ','')
entry.libelle = entry.libelle.replace('World U','World')
entry.pc_allocation = 1.0
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
request.dbsession.add(entry)
return HTTPFound(location=request.route_url('portfolio'))
else:
del form.no_id # SECURITY: prevent overwriting of primary key
form.populate_obj(entry)
# récupérer le cours du symbole de Yahoo finance
ticker = yf.Ticker(entry.symbole)
entry.cours = ticker.fast_info.last_price
entry.devise = ticker.info.get('currency')
entry.libelle = html.unescape(ticker.info.get('shortName'))
# raccourcir le libelle
entry.libelle = entry.libelle.replace('UCITS ','')
entry.libelle = entry.libelle.replace('World U','World')
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params:
PFService.delete_actif(request, entry.no_id)
request.session.flash("La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('portfolio'))
return {
'page_title': page_title,
'url': url,
'form': form,
'item': entry,
}
@view_config(route_name='actif2_edit', renderer='../templates/portfolio/actif2_edit.jinja2', permission='view')
def actif2_edit(request):
no_id = request.matchdict['no_id']
url = request.route_url('actif2_edit', no_id=no_id)
# get the list of classes
classes = PFService.get_allocation_byType(request, 'AUTRE')
if no_id == '0':
# create a new allocation
entry = Actifs()
entry.pru = 0
entry.cours = 0
entry.pc_rdt = 0
entry.ter = 0
entry.devise = 'EUR'
form = Actif2Form(request.POST, entry)
form.classe.choices = [(row.classe, row.classe) for row in classes]
page_title = "Nouvel actif"
else:
# modify post
entry = PFService.get_actifs(request, no_id)
if not entry:
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
return HTTPFound(location=request.route_url('portfolio'))
form = Actif2Form(request.POST, entry)
form.classe.choices = [(row.classe, row.classe) for row in classes]
page_title = "Modifier Actif : " + entry.symbole
if 'form.submitted' in request.params :
if no_id == '0':
form.populate_obj(entry)
entry.nombre = 1000
entry.devise = 'EUR'
entry.parite = 1.0
entry.pc_allocation = 1.0
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
request.dbsession.add(entry)
return HTTPFound(location=request.route_url('portfolio'))
else:
del form.no_id # SECURITY: prevent overwriting of primary key
form.populate_obj(entry)
entry.valeur = float(entry.cours) * entry.parite * entry.nombre;
entry.plus_value = entry.valeur - float(entry.pru * entry.nombre);
entry.pc_plusvalue = entry.plus_value / entry.valeur * 100;
entry.rendement = entry.valeur * float(entry.pc_rdt) / 100;
return HTTPFound(location=request.route_url('portfolio'))
if 'form.deleted' in request.params:
PFService.delete_actif(request, entry.no_id)
request.session.flash("La fiche a été supprimée avec succès.", 'success')
return HTTPFound(location=request.route_url('portfolio'))
return {
'page_title': page_title,
'url': url,
'form': form,
'item': entry,
}