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 taux = ticker.fast_info.get('lastPrice') PFService.update_actif_devise(request, 'USD', taux) for item in actifs: if item.Allocation.type == 'ACTION': symbole = item.Actifs.symbole # lire le cours de l'action ticker = yf.Ticker(symbole) # ticker delisted ? if symbole == 'SHLDQ': cours = 0 else: cours = round(ticker.fast_info.get('lastPrice'), 3) valeur = round(cours * item.Actifs.parite * item.Actifs.nombre, 3) plus_value = round(valeur - (item.Actifs.pru * item.Actifs.nombre),2) pc_plusvalue = round(valeur * 100 / (item.Actifs.pru * item.Actifs.nombre) - 100, 3) PFService.update_actif_valeur(request, symbole, cours, valeur, plus_value, pc_plusvalue) # time.sleep(1) # attendre 2 secondes # update du portefeuille today = datetime.datetime.now() PFService.update_portefeuille(request, today) # 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 maj_pf_le = None for item in actifs: maj_pf_le = item.Actifs.modif_le 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, 'maj_pf_le' : maj_pf_le, '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.mvt_cash = 0 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(): 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 = round(ticker.fast_info.last_price, 3) # lire le dernier histo last = PFService.get_last_histo(request) # lire les actifs et cumuler leurs valeurs actifs = PFService.get_actifs(request, '0') valeur_pf = 0 for item in actifs: valeur_pf += item.Actifs.valeur entry.valeur_pf = valeur_pf # nlle valeur part = ancienne + nouvelle ratio entry.nb_part = round(last.nb_part + (float(entry.mvt_cash) / (valeur_pf - float(entry.mvt_cash))/last.nb_part), 3) entry.val_part = round(entry.valeur_pf / entry.nb_part, 3) entry.val_part_ref = round(float(entry.cours_ref) * last.val_part_ref / last.cours_ref, 3) request.dbsession.add(entry) 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.get('lastPrice') entry.devise = ticker.fast_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 = round(float(entry.cours) * entry.parite * entry.nombre, 3) entry.plus_value = round(entry.valeur - float(entry.pru * entry.nombre), 3) entry.pc_plusvalue = round(entry.plus_value / entry.valeur * 100, 3) entry.rendement = 0 # round(entry.valeur * float(entry.pc_rdt) / 100, 3) 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) import pdb;pdb.set_trace() entry.cours = ticker.fast_info.get('lastPrice') entry.devise = ticker.fast_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 = round(float(entry.cours) * entry.parite * entry.nombre, 3) entry.plus_value = round(entry.valeur - float(entry.pru * entry.nombre), 3) entry.pc_plusvalue = round(entry.plus_value / entry.valeur * 100, 3) entry.rendement = 0 # round(entry.valeur * float(entry.pc_rdt) / 100, 3) 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, }