refonte de monaa pour remplacer caotek.fr
@@ -8,19 +8,36 @@ Author-email:
|
|||||||
License: UNKNOWN
|
License: UNKNOWN
|
||||||
Description: # README #
|
Description: # README #
|
||||||
|
|
||||||
|
Cette application permet de :
|
||||||
|
|
||||||
Cette application permet le suivi des avoirs financiers : actions, ETF, obligations (assurances-vie), livrets, etc...
|
1. faire le suivi des actifs financiers : actions, ETF, obligations (assurances-vie), livrets
|
||||||
|
2. compararer les écarts avec une allocation cible
|
||||||
|
|
||||||
|
Elle est développée avec les composants open source suivants :
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
|
- [Python](https://www.python.org/downloads/) 3.7
|
||||||
|
- [Pyramid web framework](https://trypyramid.com/) 1.10
|
||||||
|
- [MySQL server](https://mysql.com/) 5.7 sur Debian GNU/Linux 9 (stretch)
|
||||||
|
- [Apache web server](https://apache.org/) 2.4 sur Debian GNU/Linux 9 (stretch)
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
- [Bootstrap framework](https://getbootstrap.com/) for CSS 3.3.7
|
||||||
|
- [Jquery](https://jquery.com/download/) for JavaScript 3.2.1
|
||||||
|
- Chameleon templates
|
||||||
|
- [FormValidation](https://formvalidation.io/) form validator 0.7.0
|
||||||
|
|
||||||
|
## Jquery Plugins
|
||||||
|
|
||||||
|
- [DataTables](https://datatables.net/) 1.10.20
|
||||||
|
- [less.js](http://lesscss.org/) 3.11.1
|
||||||
|
- [moment.js](https://momentjs.com/) with-locales.min.js
|
||||||
|
- [Google Charts](https://developers.google.com/chart)
|
||||||
|
|
||||||
|
|
||||||
|
[Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
|
||||||
Développé avec :
|
|
||||||
- Pyramid Framework
|
|
||||||
- MySQL
|
|
||||||
- Chameleon
|
|
||||||
|
|
||||||
* [Exemple d'une comptabilité simple] (http://perso.numericable.fr/assoc1901/droit/comptabilite1.htm)
|
|
||||||
|
|
||||||
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -29,6 +46,25 @@ Description: # README #
|
|||||||
|
|
||||||
- Initial version
|
- Initial version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>>> quote.info
|
||||||
|
{'language': 'en-US', 'region': 'US', 'quoteType': 'ETF', 'quoteSourceName': 'Delayed Quote', 'currency': 'USD', 'regularMarketChange': -0.5200043,
|
||||||
|
'regularMarketOpen': 93.81, 'regularMarketDayHigh': 93.91, 'regularMarketDayLow': 92.44, 'regularMarketVolume': 4040066, 'askSize': 14,
|
||||||
|
'messageBoardId': 'finmb_22939711', 'fullExchangeName': 'NYSEArca', 'longName': 'Vanguard Real Estate Index Fund ETF Shares',
|
||||||
|
'financialCurrency': 'USD', 'averageDailyVolume3Month': 4826021, 'averageDailyVolume10Day': 4604087, 'fiftyTwoWeekLowChange': 22.009995,
|
||||||
|
'fiftyTwoWeekLowChangePercent': 0.30965102, 'fiftyTwoWeekRange': '71.08 - 94.07', 'fiftyTwoWeekHighChange': -0.98000336,
|
||||||
|
'fiftyTwoWeekHighChangePercent': -0.01041781, 'fiftyTwoWeekLow': 71.08, 'fiftyTwoWeekHigh': 94.07, 'esgPopulated': False, 'tradeable': True,
|
||||||
|
'trailingAnnualDividendRate': 3.533, 'trailingPE': 8.381201, 'trailingAnnualDividendYield': 0.037741695, 'ytdReturn': 25.76,
|
||||||
|
'trailingThreeMonthReturns': 7.14, 'trailingThreeMonthNavReturns': 7.21, 'epsTrailingTwelveMonths': 11.107, 'marketState': 'CLOSED',
|
||||||
|
'postMarketChangePercent': 0.042970154, 'postMarketTime': 1569618175, 'postMarketPrice': 93.13, 'postMarketChange': 0.040000916,
|
||||||
|
'regularMarketChangePercent': -0.55550075, 'regularMarketDayRange': '92.44 - 93.91', 'regularMarketPreviousClose': 93.61, 'bid': 93.03,
|
||||||
|
'ask': 93.13, 'bidSize': 11, 'exchange': 'PCX', 'shortName': 'Vanguard Real Estate ETF', 'exchangeDataDelayedBy': 0, 'priceHint': 2,
|
||||||
|
'sharesOutstanding': 370180992, 'bookValue': 63.751, 'fiftyDayAverage': 92.157425, 'fiftyDayAverageChange': 0.9325714,
|
||||||
|
'fiftyDayAverageChangePercent': 0.01011933, 'twoHundredDayAverage': 88.83857, 'twoHundredDayAverageChange': 4.2514267,
|
||||||
|
'twoHundredDayAverageChangePercent': 0.04785564, 'marketCap': 34460147712, 'priceToBook': 1.4602123, 'sourceInterval': 15,
|
||||||
|
'exchangeTimezoneName': 'America/New_York', 'exchangeTimezoneShortName': 'EDT', 'gmtOffSetMilliseconds': -14400000, 'triggerable': False,
|
||||||
|
'market': 'us_market', 'regularMarketPrice': 93.09, 'regularMarketTime': 1569614400, 'symbol': 'VNQ'}
|
||||||
Keywords: web wsgi bfg pylons pyramid
|
Keywords: web wsgi bfg pylons pyramid
|
||||||
Platform: UNKNOWN
|
Platform: UNKNOWN
|
||||||
Classifier: Programming Language :: Python
|
Classifier: Programming Language :: Python
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ transaction
|
|||||||
zope.sqlalchemy
|
zope.sqlalchemy
|
||||||
waitress
|
waitress
|
||||||
mysqlclient
|
mysqlclient
|
||||||
beautifulsoup4
|
yfinance
|
||||||
docutils
|
docutils
|
||||||
|
|
||||||
[testing]
|
[testing]
|
||||||
|
|||||||
@@ -29,10 +29,18 @@ def get_docs(request, doc_id):
|
|||||||
|
|
||||||
def get_docs_bytheme(request, theme):
|
def get_docs_bytheme(request, theme):
|
||||||
"""Lire les doc"""
|
"""Lire les doc"""
|
||||||
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY intitule;"
|
if theme == 'BLOG':
|
||||||
|
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY cree_le DESC LIMIT 10;"
|
||||||
|
else:
|
||||||
|
query = "SELECT * FROM docs WHERE theme=:theme ORDER BY intitule;"
|
||||||
results = request.dbsession.execute(query, {'theme': theme}).fetchall()
|
results = request.dbsession.execute(query, {'theme': theme}).fetchall()
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def get_blog_themes(request):
|
||||||
|
query = "SELECT * FROM blog_themes;"
|
||||||
|
results = request.dbsession.execute(query).fetchall()
|
||||||
|
return results
|
||||||
|
|
||||||
def update_doc(request, doc_id, intitule, texte, theme):
|
def update_doc(request, doc_id, intitule, texte, theme):
|
||||||
"""créér ou modifier le doc"""
|
"""créér ou modifier le doc"""
|
||||||
if doc_id == '0':
|
if doc_id == '0':
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ def includeme(config):
|
|||||||
config.add_route('allocation_edit', '/allocation_edit/{no_cat}')
|
config.add_route('allocation_edit', '/allocation_edit/{no_cat}')
|
||||||
config.add_route('histo_list', '/histo_list')
|
config.add_route('histo_list', '/histo_list')
|
||||||
config.add_route('histo_edit', '/histo_edit/{no_id}')
|
config.add_route('histo_edit', '/histo_edit/{no_id}')
|
||||||
|
config.add_route('portfolio', '/portfolio')
|
||||||
# members
|
# members
|
||||||
config.add_route('changer_mdp', '/changer_mdp')
|
config.add_route('changer_mdp', '/changer_mdp')
|
||||||
config.add_route('envoyer_mdp', '/envoyer_mdp')
|
config.add_route('envoyer_mdp', '/envoyer_mdp')
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
color: #404040 !important;
|
color: #000000 !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
font-size: 20px !important;
|
font-size: 20px !important;
|
||||||
letter-spacing: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar li a, .navbar .navbar-brand {
|
.navbar li a, .navbar .navbar-brand {
|
||||||
color: #404040 !important;
|
color: #000000 !important;
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +26,12 @@
|
|||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dropdown */
|
/* Dropdown */
|
||||||
.open .dropdown-toggle {
|
.open .dropdown-toggle {
|
||||||
color: #000000 ;
|
color: #000000 ;
|
||||||
@@ -43,6 +49,12 @@
|
|||||||
color: #000000 !important;
|
color: #000000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.container{
|
||||||
|
max-width: 900px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.container-fluid {
|
.container-fluid {
|
||||||
padding-top: 2em;
|
padding-top: 2em;
|
||||||
padding-bottom: 1em;
|
padding-bottom: 1em;
|
||||||
@@ -54,7 +66,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#doc-text {
|
.monospace-font {
|
||||||
font-family: Monaco, "Courier New", Courier, monospace;
|
font-family: Monaco, "Courier New", Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,9 +91,6 @@
|
|||||||
.bg-grey {
|
.bg-grey {
|
||||||
background-color: #f6f6f6;
|
background-color: #f6f6f6;
|
||||||
}
|
}
|
||||||
.logo {
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-primary {
|
.logo-primary {
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
|
|||||||
BIN
caotek_mesavoirs/static/img/blog/vpn_1.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
caotek_mesavoirs/static/img/blog/vpn_2.jpg
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
caotek_mesavoirs/static/img/blog/vpn_3.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
caotek_mesavoirs/static/img/blog/wonders_cao.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
caotek_mesavoirs/static/img/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
caotek_mesavoirs/static/img/logo-caotek.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="classe">Classe</label>
|
<label class="control-label col-xs-2" for="classe">Classe</label>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-8">
|
||||||
<select class="form-control" id="classe" name="classe">
|
<select class="form-control" id="classe" name="classe">
|
||||||
<div tal:repeat="item allocation_list">
|
<div tal:repeat="item allocation_list">
|
||||||
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
|
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-2 control-label">Identifiant</label>
|
<label class="col-xs-2 control-label">Identifiant</label>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-8">
|
||||||
<input class="form-control" type="text" name="symbole"
|
<input class="form-control" type="text" name="symbole"
|
||||||
value="${actif.symbole}" placeholder="15 caractères maximum"
|
value="${actif.symbole}" placeholder="15 caractères maximum"
|
||||||
data-fv-notempty="true"
|
data-fv-notempty="true"
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-2 control-label">Libellé</label>
|
<label class="col-xs-2 control-label">Libellé</label>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-8">
|
||||||
<input class="form-control" type="text" name="libelle"
|
<input class="form-control" type="text" name="libelle"
|
||||||
value="${actif.libelle}" placeholder="45 caractères maximum"
|
value="${actif.libelle}" placeholder="45 caractères maximum"
|
||||||
data-fv-notempty="true"
|
data-fv-notempty="true"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="pru">Total investi</label>
|
<label class="control-label col-xs-2" for="pru">Total investi</label>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">K€</div>
|
<div class="input-group-addon">K€</div>
|
||||||
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
|
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="cours">Total valeur</label>
|
<label class="control-label col-xs-2" for="cours">Total valeur</label>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">K€</div>
|
<div class="input-group-addon">K€</div>
|
||||||
<input class="form-control" type="text" id="cours" name="cours" value="${actif.cours}"
|
<input class="form-control" type="text" id="cours" name="cours" value="${actif.cours}"
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
|
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">%</div>
|
<div class="input-group-addon">%</div>
|
||||||
<input class="form-control" type="text" id="rdt" name="pc_rdt" value="${actif.pc_rdt}"
|
<input class="form-control" type="text" id="rdt" name="pc_rdt" value="${actif.pc_rdt}"
|
||||||
@@ -79,14 +79,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2">Dernière modif.</label>
|
<label class="control-label col-xs-2">Dernière modif.</label>
|
||||||
<div class="col-xs-7">
|
<div class="col-xs-8">
|
||||||
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
|
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-xs-offset-2 col-xs-10">
|
<div class="col-xs-offset-2 col-xs-10">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a class="btn btn-default" href="${request.application_url}/">
|
<a class="btn btn-default" href="${request.application_url}/portfolio">
|
||||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="classe">Classe</label>
|
<label class="control-label col-xs-2" for="classe">Classe</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<select class="form-control" id="classe" name="classe">
|
<select class="form-control" id="classe" name="classe">
|
||||||
<div tal:repeat="item allocation_list">
|
<div tal:repeat="item allocation_list">
|
||||||
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
|
<option value="${item.classe}" tal:attributes="selected actif.classe==item.classe and 'selected' or None">${item.classe}</option>
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-xs-2 control-label">Symbole FT</label>
|
<label class="col-xs-2 control-label">Symbole Yahoo</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<input class="form-control" type="text" name="symbole"
|
<input class="form-control" type="text" name="symbole"
|
||||||
value="${actif.symbole}" placeholder="15 caractères maximum"
|
value="${actif.symbole}" placeholder="15 caractères maximum"
|
||||||
data-fv-notempty="true"
|
data-fv-notempty="true"
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="nombre">Nombre</label>
|
<label class="control-label col-xs-2" for="nombre">Nombre</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<input class="form-control" type="text" id="nombre" name="nombre" value="${actif.nombre}"
|
<input class="form-control" type="text" id="nombre" name="nombre" value="${actif.nombre}"
|
||||||
data-fv-digits="true"
|
data-fv-digits="true"
|
||||||
data-fv-digits-message="Le nombre doit être composé que de chiffres" />
|
data-fv-digits-message="Le nombre doit être composé que de chiffres" />
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="pru">PRU</label>
|
<label class="control-label col-xs-2" for="pru">PRU</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">€</div>
|
<div class="input-group-addon">€</div>
|
||||||
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
|
<input class="form-control" type="text" id="pru" name="pru" value="${actif.pru}"
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="ter">TER</label>
|
<label class="control-label col-xs-2" for="ter">TER</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">%</div>
|
<div class="input-group-addon">%</div>
|
||||||
<input class="form-control" type="text" id="ter" name="ter" value="${actif.ter}"
|
<input class="form-control" type="text" id="ter" name="ter" value="${actif.ter}"
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
|
<label class="control-label col-xs-2" for="pc_rdt">% Rendement</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-8">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">%</div>
|
<div class="input-group-addon">%</div>
|
||||||
<input class="form-control" type="text" id="pc_rdt" name="pc_rdt" value="${actif.pc_rdt}"
|
<input class="form-control" type="text" id="pc_rdt" name="pc_rdt" value="${actif.pc_rdt}"
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2">Devise</label>
|
<label class="control-label col-xs-2">Devise</label>
|
||||||
<div class="col-xs-7">
|
<div class="col-xs-8">
|
||||||
<p class="form-control-static">${actif.devise}</p>
|
<p class="form-control-static">${actif.devise}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2">Dernière modif.</label>
|
<label class="control-label col-xs-2">Dernière modif.</label>
|
||||||
<div class="col-xs-7">
|
<div class="col-xs-8">
|
||||||
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
|
<p class="form-control-static" tal:condition="actif.modif_le">${actif.modif_le.strftime('%d/%m/%Y - %H:%M')}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-xs-offset-2 col-xs-10">
|
<div class="col-xs-offset-2 col-xs-10">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a class="btn btn-default" href="${request.application_url}/">
|
<a class="btn btn-default" href="${request.application_url}/portfolio">
|
||||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
<div metal:fill-slot="content">
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="${request.application_url}/" class="btn btn-default" role="button">
|
|
||||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
|
||||||
<a href="histo_edit/0" class="btn btn-success" role="button">
|
<a href="histo_edit/0" class="btn btn-success" role="button">
|
||||||
<span class="glyphicon glyphicon-plus"></span> Entrée / Sortie cash</a>
|
<span class="glyphicon glyphicon-plus"></span> Entrée / Sortie cash</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
232
caotek_mesavoirs/templates/actifs/portfolio.pt
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<metal:block use-macro="main_template">
|
||||||
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
|
<div tal:condition="message" tal:content="message" class="alert alert-success" />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="allocation_edit/0" class="btn btn-success" role="button">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span> Nouvelle classe</a>
|
||||||
|
</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<table id="categories_list" class="table table-condensed table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Classe</th>
|
||||||
|
<th class="text-right">% cible</th>
|
||||||
|
<th class="text-right">% actuel</th>
|
||||||
|
<th class="text-right">Ecart</th>
|
||||||
|
<th class="text-right">Valeur</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr tal:repeat="item items">
|
||||||
|
<td class="${item.bg_color}">${item.classe}</td>
|
||||||
|
<td class="text-right"><a href="allocation_edit/${item.no_cat}">${item.pc_cible} %</a></td>
|
||||||
|
<td class="text-right">${layout.to_percent(item.pc_atteint,1)}</td>
|
||||||
|
<td tal:condition="(item.pc_atteint - item.pc_cible)>=0" class="text-right" style="color: green;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
|
||||||
|
<td tal:condition="(item.pc_atteint - item.pc_cible) <0" class="text-right" style="color: red;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
|
||||||
|
<td class="text-right">${layout.to_euro(item.valeur)}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<table id="portfolio" class="table table-condensed table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Portefeuille</th>
|
||||||
|
<th class="text-right">Montant</th>
|
||||||
|
<th class="text-right">%</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Valorisation</td>
|
||||||
|
<td class="text-right">${layout.to_euro(member.pf_valeur)}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Plus value</td>
|
||||||
|
<td class="text-right">${layout.to_euro(member.pf_plusvalue)}</td>
|
||||||
|
<td class="text-right">${layout.to_percent(member.pf_plusvalue_pc, 1)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Rendemant brut</td>
|
||||||
|
<td class="text-right">${layout.to_euro(member.pf_rendement)}</td>
|
||||||
|
<td class="text-right">${layout.to_percent(member.pf_rdt_pc, 1)}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<b>Allocation globale</b> : 60% actions + 5% REITS + 35% obligations<br />
|
||||||
|
<b>Allocation actions D</b> (1/2) : 60% US (18%) + 30% Europe (12%)<br />
|
||||||
|
<b>Allocation actions C</b> (1/2) : 100% World (30%) <br />
|
||||||
|
[Cette allocation est inspirée de celle du <a href="https://www.nbim.no/en/the-fund/how-we-invest/benchmark-index/">Fond souverain Norvégien</a>]
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<!-- graphique donut cible -->
|
||||||
|
<div id="donutchart_cible" style="width: 100%; height: 500px;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<!-- graphique donut actuel -->
|
||||||
|
<div id="donutchart_actuel" style="width: 100%; height: 500px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<h3>Mes actifs</h3>
|
||||||
|
<p>"<i>Diversification is not determined by the number of securities held.</i>"
|
||||||
|
<a href="http://www.etf.com/sections/index-investor-corner" target="_blank">Larry Swedroe</a></p>
|
||||||
|
|
||||||
|
<form id="actif_list-form" action="${url}" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<button id="updateButton" class="btn btn-primary" type="submit" name="form.submitted">
|
||||||
|
<i class="glyphicon glyphicon-refresh"></i> MAJ du portefeuille</button>
|
||||||
|
<a href="#" class="btn btn-success" role="button"
|
||||||
|
data-toggle="modal" data-target="#choixTypeActif"><span class="glyphicon glyphicon-plus"></span> Nouvel actif</a>
|
||||||
|
<a href="${request.application_url}/histo_list" class="btn btn-default" role="button">
|
||||||
|
<span class="glyphicon glyphicon-stats"></span> Historique</a>
|
||||||
|
<a href="${request.application_url}/doc_view/2" class="btn btn-default" role="button">
|
||||||
|
<span class="glyphicon glyphicon-folder-close"></span> Mouvements</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table id="actifs_list" class="table table-condensed table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Classe</th>
|
||||||
|
<th>Libellé</th>
|
||||||
|
<th class="text-right">Cours</th>
|
||||||
|
<th class="text-right">Nb</th>
|
||||||
|
<th class="text-right">Valeur</th>
|
||||||
|
<th class="text-right">+/- Valeur</th>
|
||||||
|
<th class="text-right">% de +/-</th>
|
||||||
|
<th class="text-right">Rdt brut</th>
|
||||||
|
<th class="text-right">% Rdt</th>
|
||||||
|
<th class="text-right">% PF</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr tal:repeat="ligne actifs">
|
||||||
|
<td class="${ligne.bg_color}">${ligne.classe}</td>
|
||||||
|
<td tal:condition="ligne.type=='ACTION'"><a href="actif_edit/${ligne.no_id}">${ligne.libelle}</a></td>
|
||||||
|
<td tal:condition="ligne.type!='ACTION'"><a href="actif2_edit/${ligne.no_id}">${ligne.libelle}</a></td>
|
||||||
|
<td tal:condition="ligne.devise=='EUR'" class="text-right">${layout.to_euro(ligne.cours)}</td>
|
||||||
|
<td tal:condition="ligne.devise=='USD'" class="text-right">${layout.to_usd(ligne.cours)}</td>
|
||||||
|
<td class="text-right">${ligne.nombre}</td>
|
||||||
|
<td class="text-right">${layout.to_euro(ligne.valeur)}</td>
|
||||||
|
<td tal:condition="ligne.plus_value>=0" class="text-right" style="color: green;">${layout.to_euro(ligne.plus_value)}</td>
|
||||||
|
<td tal:condition="ligne.plus_value <0" class="text-right" style="color: red;">${layout.to_euro(ligne.plus_value)}</td>
|
||||||
|
<td tal:condition="ligne.pc_plusvalue>=0" class="text-right" style="color: green;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
|
||||||
|
<td tal:condition="ligne.pc_plusvalue <0" class="text-right" style="color: red;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
|
||||||
|
<td class="text-right">${u'%.0f €' % (ligne.rendement)}</td>
|
||||||
|
<td class="text-right">${layout.to_percent(ligne.pc_rdt,1)}</td>
|
||||||
|
<td class="text-right">${ligne.pc_allocation} %</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="text-right" colspan="4"><b>Total</b></td>
|
||||||
|
<td tal:condition="total_valeur>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_valeur)}</b></td>
|
||||||
|
<td tal:condition="total_valeur <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_valeur)}</b></td>
|
||||||
|
<td tal:condition="total_pv>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_pv)}</b></td>
|
||||||
|
<td tal:condition="total_pv <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_pv)}</b></td>
|
||||||
|
<td class="text-right"><b>${layout.to_percent(total_pc_value, 1)}</b></td>
|
||||||
|
<td class="text-right"><b>${total_rdt} €</b></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="text-right"><b>100.0 %</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div>
|
||||||
|
<!-- graphique evolution -->
|
||||||
|
<div id="curve_chart" style="width: 100%; height: 500px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MODAL POPUP : Affichage de la FAQ -->
|
||||||
|
<div class="modal fade" id="choixTypeActif" tabindex="-1" role="dialog" aria-labelledby="choixTypeActif" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></button>
|
||||||
|
<h4 class="modal-title" id="choixTypeActif">Choix du type d'actif à créer</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>
|
||||||
|
Voulez-vous créer un actif de type <br />
|
||||||
|
<br />
|
||||||
|
<a href="${request.application_url}/actif_edit/0" class="btn btn-primary" role="button">
|
||||||
|
ACTION</a> ou
|
||||||
|
<a href="${request.application_url}/actif2_edit/0" class="btn btn-warning" role="button">
|
||||||
|
AUTRE</a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#updateButton').on('click', function(){
|
||||||
|
$('i.gly-spin').removeClass('gly-spin');
|
||||||
|
$('i').addClass('gly-spin');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
google.charts.load("current", {packages:["corechart"]});
|
||||||
|
google.charts.setOnLoadCallback(drawChart);
|
||||||
|
var dataSet_cible = ${donut_cible};
|
||||||
|
var dataSet_actuel = ${donut_actuel};
|
||||||
|
var dataSet_evoln = ${courbe_evoln};
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
var data_cible = google.visualization.arrayToDataTable(dataSet_cible);
|
||||||
|
var data_actuel = google.visualization.arrayToDataTable(dataSet_actuel);
|
||||||
|
var data_evoln = google.visualization.arrayToDataTable(dataSet_evoln);
|
||||||
|
|
||||||
|
var options_cible = {
|
||||||
|
title: 'Allocation cible',
|
||||||
|
pieHole: 0.4,
|
||||||
|
slices: {
|
||||||
|
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
|
||||||
|
2: {color: 'Maroon'}, 3: {color: 'Brown'},
|
||||||
|
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var options_actuel = {
|
||||||
|
title: 'Allocation actuelle',
|
||||||
|
pieHole: 0.4,
|
||||||
|
slices: {
|
||||||
|
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
|
||||||
|
2: {color: 'Maroon'}, 3: {color: 'Brown'},
|
||||||
|
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var options_evoln = {
|
||||||
|
title: 'Evolution du portefeuille VS fond Carmignac Investissement',
|
||||||
|
curveType: 'function',
|
||||||
|
legend: { position: 'top' }
|
||||||
|
};
|
||||||
|
|
||||||
|
var chart_cible = new google.visualization.PieChart(document.getElementById('donutchart_cible'));
|
||||||
|
chart_cible.draw(data_cible, options_cible);
|
||||||
|
var chart_actuel = new google.visualization.PieChart(document.getElementById('donutchart_actuel'));
|
||||||
|
chart_actuel.draw(data_actuel, options_actuel);
|
||||||
|
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
|
||||||
|
chart.draw(data_evoln, options_evoln);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</div><!-- content -->
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
@@ -8,30 +8,29 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="intitule">Intitulé</label>
|
<label class="control-label col-xs-2" for="intitule">Intitulé</label>
|
||||||
<div class="col-xs-8">
|
<div class="col-xs-10">
|
||||||
<input class="form-control" type="text" id="intitule" name="intitule" value="${intitule}"
|
<input class="form-control" type="text" id="intitule" name="intitule" value="${intitule}"
|
||||||
placeholder="40 caractères maximum"
|
|
||||||
data-fv-notempty="true"
|
data-fv-notempty="true"
|
||||||
data-fv-notempty-message="L'intitule est obligatoire"
|
data-fv-notempty-message="L'intitule est obligatoire"
|
||||||
data-fv-stringlength="true"
|
data-fv-stringlength="true"
|
||||||
data-fv-stringlength-max="40"
|
data-fv-stringlength-max="100"
|
||||||
data-fv-stringlength-message="40 caractères maximum" />
|
data-fv-stringlength-message="100 caractères maximum" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="texte">Texte</label>
|
<label class="control-label col-xs-2" for="texte">Texte</label>
|
||||||
<div class="col-xs-8">
|
<div class="col-xs-10">
|
||||||
<textarea class="form-control" rows="15" cols="40" id="texte" name="texte">${texte}</textarea>
|
<textarea class="form-control monospace-font" rows="15" cols="40" id="texte" name="texte">${texte}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-xs-2" for="theme">Thème</label>
|
<label class="control-label col-xs-2" for="theme">Thème</label>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-6">
|
||||||
<select class="form-control" id="theme" name="theme">
|
<select class="form-control" id="theme" name="theme">
|
||||||
<div tal:repeat="item themes">
|
<div tal:repeat="item themes">
|
||||||
<option value="${item}" tal:attributes="selected theme==item and 'selected' or None">${item}</option>
|
<option value="${item.theme}" tal:attributes="selected theme==item.theme and 'selected' or None">${item.theme}</option>
|
||||||
</div>
|
</div>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,16 +65,6 @@ $(document).ready(function() {
|
|||||||
invalid: 'glyphicon glyphicon-remove',
|
invalid: 'glyphicon glyphicon-remove',
|
||||||
validating: 'glyphicon glyphicon-refresh'
|
validating: 'glyphicon glyphicon-refresh'
|
||||||
},
|
},
|
||||||
fields: {
|
|
||||||
texte: {
|
|
||||||
validators: {
|
|
||||||
stringLength: {
|
|
||||||
max: 30000,
|
|
||||||
message: '30000 caractères maximum'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
$('form input').on('keypress', function(e) {
|
$('form input').on('keypress', function(e) {
|
||||||
return e.which !== 13;
|
return e.which !== 13;
|
||||||
|
|||||||
@@ -7,35 +7,24 @@
|
|||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
Créér une nouvelle doc</a>
|
Créér une nouvelle doc</a>
|
||||||
</p>
|
</p>
|
||||||
<div class="col-md-4">
|
<div class="col-md-6">
|
||||||
<table class="table table-condensed table-striped table-bordered">
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
<tr>
|
<tr>
|
||||||
<th>FINANCE</th>
|
<th>MEMOS</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr tal:repeat="ligne docs_finance">
|
<tr tal:repeat="ligne memos">
|
||||||
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-6">
|
||||||
<table class="table table-condensed table-striped table-bordered">
|
<table class="table table-condensed table-striped table-bordered">
|
||||||
<tr>
|
<tr>
|
||||||
<th>VOITURE</th>
|
<th>DOCUMENTS</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr tal:repeat="ligne docs_voiture">
|
<tr tal:repeat="ligne docs">
|
||||||
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<table class="table table-condensed table-striped table-bordered">
|
|
||||||
<tr>
|
|
||||||
<th class="text-center">MAISON</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr tal:repeat="ligne docs_maison">
|
|
||||||
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
<td><a href="doc_view/${ligne.doc_id}">${ligne.intitule}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,232 +1,31 @@
|
|||||||
<metal:block use-macro="main_template">
|
<metal:block use-macro="main_template">
|
||||||
<div metal:fill-slot="content">
|
<div metal:fill-slot="content">
|
||||||
|
|
||||||
<div tal:condition="message" tal:content="message" class="alert alert-success" />
|
<h1>Blog</h1>
|
||||||
|
<p tal:condition="not layout.isAnonymous()">
|
||||||
<p>
|
<a href="doc_edit/0">Créer un nouveau post</a>
|
||||||
<a href="allocation_edit/0" class="btn btn-success" role="button">
|
</p>
|
||||||
<span class="glyphicon glyphicon-plus"></span> Nouvelle classe</a>
|
|
||||||
</p>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<table id="categories_list" class="table table-condensed table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Classe</th>
|
|
||||||
<th class="text-right">% cible</th>
|
|
||||||
<th class="text-right">% actuel</th>
|
|
||||||
<th class="text-right">Ecart</th>
|
|
||||||
<th class="text-right">Valeur</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr tal:repeat="item items">
|
|
||||||
<td class="${item.bg_color}">${item.classe}</td>
|
|
||||||
<td class="text-right"><a href="allocation_edit/${item.no_cat}">${item.pc_cible} %</a></td>
|
|
||||||
<td class="text-right">${layout.to_percent(item.pc_atteint,1)}</td>
|
|
||||||
<td tal:condition="(item.pc_atteint - item.pc_cible)>=0" class="text-right" style="color: green;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
|
|
||||||
<td tal:condition="(item.pc_atteint - item.pc_cible) <0" class="text-right" style="color: red;">${layout.to_percent(item.pc_atteint - item.pc_cible,1)}</td>
|
|
||||||
<td class="text-right">${layout.to_euro(item.valeur)}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<table id="portfolio" class="table table-condensed table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Portefeuille</th>
|
|
||||||
<th class="text-right">Montant</th>
|
|
||||||
<th class="text-right">%</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Valorisation</td>
|
|
||||||
<td class="text-right">${layout.to_euro(member.pf_valeur)}</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Plus value</td>
|
|
||||||
<td class="text-right">${layout.to_euro(member.pf_plusvalue)}</td>
|
|
||||||
<td class="text-right">${layout.to_percent(member.pf_plusvalue_pc, 1)}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Rendemant brut</td>
|
|
||||||
<td class="text-right">${layout.to_euro(member.pf_rendement)}</td>
|
|
||||||
<td class="text-right">${layout.to_percent(member.pf_rdt_pc, 1)}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<b>Allocation globale</b> : 60% actions + 5% REITS + 35% obligations<br />
|
|
||||||
<b>Allocation actions D</b> (1/2) : 60% US (18%) + 30% Europe (12%)<br />
|
|
||||||
<b>Allocation actions C</b> (1/2) : 100% World (30%) <br />
|
|
||||||
[Cette allocation est inspirée de celle du <a href="https://www.nbim.no/en/the-fund/how-we-invest/benchmark-index/">Fond souverain Norvégien</a>]
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<table class="table">
|
||||||
<!-- graphique donut cible -->
|
<tr tal:repeat="ligne items">
|
||||||
<div id="donutchart_cible" style="width: 100%; height: 500px;"></div>
|
<td>${ligne.cree_le.strftime("%Y")}</td>
|
||||||
</div>
|
<td>${ligne.cree_le.strftime("%d %b")}</td>
|
||||||
<div class="col-md-6">
|
<td><a href="doc_view/${ligne.doc_id}"><b>${ligne.intitule}</b></a></td>
|
||||||
<!-- graphique donut actuel -->
|
|
||||||
<div id="donutchart_actuel" style="width: 100%; height: 500px;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<h3>Mes actifs</h3>
|
|
||||||
<p>"<i>Diversification is not determined by the number of securities held.</i>"
|
|
||||||
<a href="http://www.etf.com/sections/index-investor-corner" target="_blank">Larry Swedroe</a></p>
|
|
||||||
|
|
||||||
<form id="actif_list-form" action="${url}" method="post">
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-group">
|
|
||||||
<button id="updateButton" class="btn btn-primary" type="submit" name="form.submitted">
|
|
||||||
<i class="glyphicon glyphicon-refresh"></i> MAJ du portefeuille</button>
|
|
||||||
<a href="#" class="btn btn-success" role="button"
|
|
||||||
data-toggle="modal" data-target="#choixTypeActif"><span class="glyphicon glyphicon-plus"></span> Nouvel actif</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<table id="actifs_list" class="table table-condensed table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Classe</th>
|
|
||||||
<th>Libellé</th>
|
|
||||||
<th class="text-right">Cours</th>
|
|
||||||
<th class="text-right">Nb</th>
|
|
||||||
<th class="text-right">Valeur</th>
|
|
||||||
<th class="text-right">+/- Valeur</th>
|
|
||||||
<th class="text-right">% de +/-</th>
|
|
||||||
<th class="text-right">Rdt brut</th>
|
|
||||||
<th class="text-right">% Rdt</th>
|
|
||||||
<th class="text-right">% PF</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr tal:repeat="ligne actifs">
|
|
||||||
<td class="${ligne.bg_color}">${ligne.classe}</td>
|
|
||||||
<td tal:condition="ligne.type=='ACTION'"><a href="actif_edit/${ligne.no_id}">${ligne.libelle}</a></td>
|
|
||||||
<td tal:condition="ligne.type!='ACTION'"><a href="actif2_edit/${ligne.no_id}">${ligne.libelle}</a></td>
|
|
||||||
<td tal:condition="ligne.devise=='EUR'" class="text-right">${layout.to_euro(ligne.cours)}</td>
|
|
||||||
<td tal:condition="ligne.devise=='USD'" class="text-right">${layout.to_usd(ligne.cours)}</td>
|
|
||||||
<td class="text-right">${ligne.nombre}</td>
|
|
||||||
<td class="text-right">${layout.to_euro(ligne.valeur)}</td>
|
|
||||||
<td tal:condition="ligne.plus_value>=0" class="text-right" style="color: green;">${layout.to_euro(ligne.plus_value)}</td>
|
|
||||||
<td tal:condition="ligne.plus_value <0" class="text-right" style="color: red;">${layout.to_euro(ligne.plus_value)}</td>
|
|
||||||
<td tal:condition="ligne.pc_plusvalue>=0" class="text-right" style="color: green;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
|
|
||||||
<td tal:condition="ligne.pc_plusvalue <0" class="text-right" style="color: red;">${layout.to_percent(ligne.pc_plusvalue,1)}</td>
|
|
||||||
<td class="text-right">${u'%.0f €' % (ligne.rendement)}</td>
|
|
||||||
<td class="text-right">${layout.to_percent(ligne.pc_rdt,1)}</td>
|
|
||||||
<td class="text-right">${ligne.pc_allocation} %</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-right" colspan="4"><b>Total</b></td>
|
|
||||||
<td tal:condition="total_valeur>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_valeur)}</b></td>
|
|
||||||
<td tal:condition="total_valeur <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_valeur)}</b></td>
|
|
||||||
<td tal:condition="total_pv>=0" class="text-right" style="color: green;"><b>${layout.to_euro(total_pv)}</b></td>
|
|
||||||
<td tal:condition="total_pv <0" class="text-right" style="color: red;"><b>${layout.to_euro(total_pv)}</b></td>
|
|
||||||
<td class="text-right"><b>${layout.to_percent(total_pc_value, 1)}</b></td>
|
|
||||||
<td class="text-right"><b>${total_rdt} €</b></td>
|
|
||||||
<td></td>
|
|
||||||
<td class="text-right"><b>100.0 %</b></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row well text-center" tal:condition="not layout.isAnonymous()">
|
||||||
<div class="col-md-6">
|
<div class="col-sm-3">
|
||||||
<!-- graphique evolution -->
|
<a href="${request.application_url}/portfolio"><span class="glyphicon glyphicon-piggy-bank logo-primary"></span></a>
|
||||||
<div id="curve_chart" style="width: 200%; height: 500px;"></div>
|
<h4>EPARGNE</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-sm-3">
|
||||||
|
<a href="${request.application_url}/doc_list"><span class="glyphicon glyphicon-list-alt logo-primary"></span></a>
|
||||||
|
<h4>MEMOS</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MODAL POPUP : Affichage de la FAQ -->
|
|
||||||
<div class="modal fade" id="choixTypeActif" tabindex="-1" role="dialog" aria-labelledby="choixTypeActif" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></button>
|
|
||||||
<h4 class="modal-title" id="choixTypeActif">Choix du type d'actif à créer</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>
|
|
||||||
Voulez-vous créer un actif de type <br />
|
|
||||||
<br />
|
|
||||||
<a href="${request.application_url}/actif_edit/0" class="btn btn-primary" role="button">
|
|
||||||
ACTION</a> ou
|
|
||||||
<a href="${request.application_url}/actif2_edit/0" class="btn btn-warning" role="button">
|
|
||||||
AUTRE</a>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#updateButton').on('click', function(){
|
|
||||||
$('i.gly-spin').removeClass('gly-spin');
|
|
||||||
$('i').addClass('gly-spin');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
google.charts.load("current", {packages:["corechart"]});
|
|
||||||
google.charts.setOnLoadCallback(drawChart);
|
|
||||||
var dataSet_cible = ${donut_cible};
|
|
||||||
var dataSet_actuel = ${donut_actuel};
|
|
||||||
var dataSet_evoln = ${courbe_evoln};
|
|
||||||
|
|
||||||
function drawChart() {
|
|
||||||
var data_cible = google.visualization.arrayToDataTable(dataSet_cible);
|
|
||||||
var data_actuel = google.visualization.arrayToDataTable(dataSet_actuel);
|
|
||||||
var data_evoln = google.visualization.arrayToDataTable(dataSet_evoln);
|
|
||||||
|
|
||||||
var options_cible = {
|
|
||||||
title: 'Allocation cible',
|
|
||||||
pieHole: 0.4,
|
|
||||||
slices: {
|
|
||||||
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
|
|
||||||
2: {color: 'Maroon'}, 3: {color: 'Brown'},
|
|
||||||
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
var options_actuel = {
|
|
||||||
title: 'Allocation actuelle',
|
|
||||||
pieHole: 0.4,
|
|
||||||
slices: {
|
|
||||||
0: {color: 'SteelBlue'}, 1: {color: 'LightSteelBlue'},
|
|
||||||
2: {color: 'Maroon'}, 3: {color: 'Brown'},
|
|
||||||
5: {offset: 0.2, color: 'DarkGreen'}, 6: {offset: 0.3, color: 'Green'},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
var options_evoln = {
|
|
||||||
title: 'Evolution du portefeuille VS fond Carmignac Investissement',
|
|
||||||
curveType: 'function',
|
|
||||||
legend: { position: 'top' }
|
|
||||||
};
|
|
||||||
|
|
||||||
var chart_cible = new google.visualization.PieChart(document.getElementById('donutchart_cible'));
|
|
||||||
chart_cible.draw(data_cible, options_cible);
|
|
||||||
var chart_actuel = new google.visualization.PieChart(document.getElementById('donutchart_actuel'));
|
|
||||||
chart_actuel.draw(data_actuel, options_actuel);
|
|
||||||
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
|
|
||||||
chart.draw(data_evoln, options_evoln);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div><!-- content -->
|
</div><!-- content -->
|
||||||
</metal:block>
|
</metal:block>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<title>${page_title}</title>
|
<title>${page_title}</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" />
|
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" />
|
||||||
|
<link rel="shortcut icon" href="${request.static_url('caotek_mesavoirs:static/img/favicon.ico')}">
|
||||||
|
|
||||||
<!-- Bootstrap core + Plug-ins CSS -->
|
<!-- Bootstrap core + Plug-ins CSS -->
|
||||||
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||||
@@ -48,26 +49,24 @@
|
|||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a href="${request.application_url}" alt="Accueil">
|
<a class="navbar-brand" class="text-center" href="${request.application_url}" alt="Accueil">
|
||||||
<img src="${request.static_url('caotek_mesavoirs:static/img/logo.png')}" class="logo" /></a>
|
<img src="${request.static_url('caotek_mesavoirs:static/img/logo-caotek.png')}" class="logo" /></a>
|
||||||
MON PORTEFEUILLE
|
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse" id="myNavbar" tal:condition="not layout.isAnonymous()">
|
<div class="collapse navbar-collapse" id="myNavbar">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li><a href="${request.application_url}/histo_list">HISTORIQUE</a></li>
|
<!-- <li><a href="${request.application_url}/histo_list">HISTORIQUE</a></li> -->
|
||||||
<li><a href="${request.application_url}/doc_list">DOCS</a></li>
|
<li tal:condition="layout.isAnonymous()"><a href="${request.application_url}/login">se connecter</a></li>
|
||||||
${panel('dropdown_menu_panel')}
|
${panel('dropdown_menu_panel')}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>${page_title}</h1>
|
<h1 tal:condition="request.path != '/'">${page_title}</h1>
|
||||||
<br />
|
|
||||||
<div id="messages" tal:attributes="class request.is_xhr and 'ajax-replace' or None">
|
<div id="messages" tal:attributes="class request.is_xhr and 'ajax-replace' or None">
|
||||||
<div tal:repeat="queue ('', 'info', 'success', 'warning', 'danger')"
|
<div tal:repeat="queue ('', 'info', 'success', 'warning', 'danger')"
|
||||||
tal:omit-tag="">
|
tal:omit-tag="">
|
||||||
@@ -86,8 +85,24 @@
|
|||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="container-fluid bg-footer text-center">
|
<footer class="container-fluid bg-footer">
|
||||||
<p>© 2017 - www.caotek.fr - Powered by <a href="https://trypyramid.com/">Pyramid</a></p>
|
<div class="row">
|
||||||
|
<div class="col-xs-offset-2 col-xs-4">
|
||||||
|
<p>L'argent que l'on possède est l'instrument de la liberté; celui que l'on pourchasse est celui de la servitude - <b>Rousseau</b></p>
|
||||||
|
<p>L'intelligence ce n'est pas ce que l'on sait mais ce que l'on fait quand on ne sait pas - <b>Jean Piaget</b></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-offset-2 col-xs-4">
|
||||||
|
<p>
|
||||||
|
Apprendre Restructured Text <a href="https://github.com/ralsina/rst-cheatsheet/blob/master/rst-cheatsheet.rst">(reST)</a><br />
|
||||||
|
Apprendre Markdown <a href="https://www.markdownguide.org/basic-syntax/">(md)</a><br />
|
||||||
|
<a href="http://www.marinestylefitness.com/">Marine Style Fitness </a><br />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="row">
|
||||||
|
<p class="text-center">© 2017 - www.caotek.fr - Powered by <a href="https://trypyramid.com/">Pyramid</a></p>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<div metal:define-slot="additional_scripts" />
|
<div metal:define-slot="additional_scripts" />
|
||||||
|
|||||||
@@ -34,6 +34,97 @@ import time
|
|||||||
import yfinance as yf
|
import yfinance as yf
|
||||||
import html
|
import html
|
||||||
|
|
||||||
|
@view_config(route_name='portfolio', renderer='../templates/actifs/portfolio.pt', permission='view')
|
||||||
|
def portfolio(request):
|
||||||
|
logged_in = request.authenticated_userid
|
||||||
|
member = get_member_by_email(request, logged_in)
|
||||||
|
url = request.route_url('portfolio')
|
||||||
|
|
||||||
|
message = ''
|
||||||
|
|
||||||
|
# lire les categories
|
||||||
|
items = 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
|
||||||
|
|
||||||
|
if total != 100:
|
||||||
|
message = 'Attention, le total de votre répartition cible est incorrect : %s.' % total
|
||||||
|
|
||||||
|
# lire les actifs
|
||||||
|
actifs = 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
|
||||||
|
update_actif_devise(request, 'USD', ticker.info.get('regularMarketPrice'))
|
||||||
|
|
||||||
|
for item in actifs:
|
||||||
|
if item.type == 'ACTION':
|
||||||
|
# lire le cours de l'action
|
||||||
|
ticker = yf.Ticker(item.symbole)
|
||||||
|
# caluler son rendement
|
||||||
|
dividends = get_dividends(ticker)
|
||||||
|
update_actif_valeur(request, item.symbole, ticker.info.get('regularMarketPrice'), dividends)
|
||||||
|
time.sleep(1) # attendre 2 secondes
|
||||||
|
|
||||||
|
# update du portefeuille
|
||||||
|
update_portefeuille(request, logged_in)
|
||||||
|
# relire les actifs
|
||||||
|
actifs = get_actifs(request, '0')
|
||||||
|
message = 'Le portefeuille est mis à jour avec succès.'
|
||||||
|
|
||||||
|
total_valeur = 0
|
||||||
|
total_pv = 0
|
||||||
|
total_rdt = 0
|
||||||
|
for item in actifs:
|
||||||
|
total_valeur += item.valeur
|
||||||
|
total_pv += item.plus_value
|
||||||
|
total_pc_value = total_pv / total_valeur * 100
|
||||||
|
total_rdt += item.rendement
|
||||||
|
|
||||||
|
# lire l'historique
|
||||||
|
histos = 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",
|
||||||
|
'message': message,
|
||||||
|
'url': url,
|
||||||
|
'items': items,
|
||||||
|
'member': member,
|
||||||
|
'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
|
||||||
|
}
|
||||||
|
|
||||||
@view_config(route_name='actif_edit', renderer='../templates/actifs/actif_edit.pt', permission='view')
|
@view_config(route_name='actif_edit', renderer='../templates/actifs/actif_edit.pt', permission='view')
|
||||||
def actif_edit(request):
|
def actif_edit(request):
|
||||||
no_id = request.matchdict['no_id']
|
no_id = request.matchdict['no_id']
|
||||||
@@ -61,7 +152,7 @@ def actif_edit(request):
|
|||||||
actif = get_actifs(request, no_id)
|
actif = get_actifs(request, no_id)
|
||||||
if not actif:
|
if not actif:
|
||||||
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
page_title= "Actif ACTION : %s" % (actif.libelle)
|
page_title= "Actif ACTION : %s" % (actif.libelle)
|
||||||
|
|
||||||
if 'form.submitted' in request.params:
|
if 'form.submitted' in request.params:
|
||||||
@@ -80,16 +171,15 @@ def actif_edit(request):
|
|||||||
ticker = yf.Ticker(symbole)
|
ticker = yf.Ticker(symbole)
|
||||||
new_values['cours'] = ticker.info.get('regularMarketPrice')
|
new_values['cours'] = ticker.info.get('regularMarketPrice')
|
||||||
new_values['devise'] = ticker.info.get('currency')
|
new_values['devise'] = ticker.info.get('currency')
|
||||||
longName = html.unescape(ticker.info.get('longName'))
|
new_values['libelle'] = html.unescape(ticker.info.get('shortName'))
|
||||||
new_values['libelle'] = longName.replace('Vanguard Funds Public Limited Company - ','').replace('Amundi Index Solutions - ','').replace('Distributing','')
|
|
||||||
update_actif(request, no_id, new_values)
|
update_actif(request, no_id, new_values)
|
||||||
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
if 'form.deleted' in request.params:
|
if 'form.deleted' in request.params:
|
||||||
delete_actif(request, no_id)
|
delete_actif(request, no_id)
|
||||||
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'page_title': page_title,
|
'page_title': page_title,
|
||||||
@@ -124,7 +214,7 @@ def actif2_edit(request):
|
|||||||
actif = get_actifs(request, no_id)
|
actif = get_actifs(request, no_id)
|
||||||
if not actif:
|
if not actif:
|
||||||
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
request.session.flash(u"Actif non trouvé : %s" % no_id, 'warning')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
page_title= "Actif : %s" % (actif.symbole)
|
page_title= "Actif : %s" % (actif.symbole)
|
||||||
|
|
||||||
if 'form.submitted' in request.params:
|
if 'form.submitted' in request.params:
|
||||||
@@ -137,12 +227,12 @@ def actif2_edit(request):
|
|||||||
new_values['devise'] = 'EUR'
|
new_values['devise'] = 'EUR'
|
||||||
update_actif(request, no_id, new_values)
|
update_actif(request, no_id, new_values)
|
||||||
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
if 'form.deleted' in request.params:
|
if 'form.deleted' in request.params:
|
||||||
delete_actif(request, no_id)
|
delete_actif(request, no_id)
|
||||||
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'page_title': page_title,
|
'page_title': page_title,
|
||||||
@@ -174,7 +264,7 @@ def allocation_edit(request):
|
|||||||
allocation = get_allocation(request, no_cat)
|
allocation = get_allocation(request, no_cat)
|
||||||
if not allocation:
|
if not allocation:
|
||||||
request.session.flash(u"Classe non trouvé : %s" % no_cat, 'warning')
|
request.session.flash(u"Classe non trouvé : %s" % no_cat, 'warning')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
page_title= "Classe : %s" % (allocation.classe)
|
page_title= "Classe : %s" % (allocation.classe)
|
||||||
|
|
||||||
if 'form.submitted' in request.params:
|
if 'form.submitted' in request.params:
|
||||||
@@ -186,12 +276,12 @@ def allocation_edit(request):
|
|||||||
if new_values:
|
if new_values:
|
||||||
update_allocation(request, no_cat, new_values)
|
update_allocation(request, no_cat, new_values)
|
||||||
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
request.session.flash(u"La fiche a été mise à jour avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
if 'form.deleted' in request.params:
|
if 'form.deleted' in request.params:
|
||||||
delete_allocation(request, no_cat)
|
delete_allocation(request, no_cat)
|
||||||
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
request.session.flash(u"La fiche a été supprimée avec succès.", 'success')
|
||||||
return HTTPFound(location=request.route_url('home'))
|
return HTTPFound(location=request.route_url('portfolio'))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'page_title': page_title,
|
'page_title': page_title,
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ from sqlalchemy.exc import DBAPIError
|
|||||||
from ..security import groupfinder
|
from ..security import groupfinder
|
||||||
|
|
||||||
from ..models.default import *
|
from ..models.default import *
|
||||||
from ..models.actifs import *
|
|
||||||
from ..models.members import (
|
|
||||||
get_member_by_email,
|
|
||||||
)
|
|
||||||
|
|
||||||
# import datetime
|
# import datetime
|
||||||
import time
|
import time
|
||||||
@@ -70,110 +66,28 @@ def to_percent(x, d):
|
|||||||
return pc.replace('.', ',')
|
return pc.replace('.', ',')
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='home', renderer='../templates/home.pt', permission='view')
|
@view_config(route_name='home', renderer='../templates/home.pt')
|
||||||
def home(request):
|
def home(request):
|
||||||
logged_in = request.authenticated_userid
|
|
||||||
member = get_member_by_email(request, logged_in)
|
|
||||||
url = request.route_url('home')
|
|
||||||
|
|
||||||
message = ''
|
# lire toutes les docs
|
||||||
|
items = get_docs_bytheme(request, 'BLOG')
|
||||||
# lire les categories
|
|
||||||
items = 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
|
|
||||||
|
|
||||||
if total != 100:
|
|
||||||
message = 'Attention, le total de votre répartition cible est incorrect : %s.' % total
|
|
||||||
|
|
||||||
# lire les actifs
|
|
||||||
actifs = 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
|
|
||||||
update_actif_devise(request, 'USD', ticker.info.get('regularMarketPrice'))
|
|
||||||
|
|
||||||
for item in actifs:
|
|
||||||
if item.type == 'ACTION':
|
|
||||||
# lire le cours de l'action
|
|
||||||
ticker = yf.Ticker(item.symbole)
|
|
||||||
# caluler son rendement
|
|
||||||
dividends = get_dividends(ticker)
|
|
||||||
update_actif_valeur(request, item.symbole, ticker.info.get('regularMarketPrice'), dividends)
|
|
||||||
time.sleep(1) # attendre 2 secondes
|
|
||||||
|
|
||||||
# update du portefeuille
|
|
||||||
update_portefeuille(request, logged_in)
|
|
||||||
# relire les actifs
|
|
||||||
actifs = get_actifs(request, '0')
|
|
||||||
message = 'Le portefeuille est mis à jour avec succès.'
|
|
||||||
|
|
||||||
total_valeur = 0
|
|
||||||
total_pv = 0
|
|
||||||
total_rdt = 0
|
|
||||||
for item in actifs:
|
|
||||||
total_valeur += item.valeur
|
|
||||||
total_pv += item.plus_value
|
|
||||||
total_pc_value = total_pv / total_valeur * 100
|
|
||||||
total_rdt += item.rendement
|
|
||||||
|
|
||||||
# lire l'historique
|
|
||||||
histos = 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 {
|
return {
|
||||||
'page_title': "Allocation d'actifs",
|
'page_title': "Home",
|
||||||
'message': message,
|
|
||||||
'url': url,
|
|
||||||
'items': items,
|
'items': items,
|
||||||
'member': member,
|
|
||||||
'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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@view_config(route_name='doc_list', renderer='../templates/doc_list.pt', permission='view')
|
@view_config(route_name='doc_list', renderer='../templates/doc_list.pt', permission='view')
|
||||||
def doc_list(request):
|
def doc_list(request):
|
||||||
|
|
||||||
# lire toutes les docs
|
# lire toutes les docs
|
||||||
docs_finance = get_docs_bytheme(request, 'FINANCE')
|
memos = get_docs_bytheme(request, 'memo')
|
||||||
docs_maison = get_docs_bytheme(request, 'MAISON')
|
docs = get_docs_bytheme(request, 'doc')
|
||||||
docs_voiture = get_docs_bytheme(request, 'VOITURE')
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'page_title': "Documents",
|
'page_title': "Documents",
|
||||||
'docs_finance': docs_finance,
|
'memos': memos,
|
||||||
'docs_maison': docs_maison,
|
'docs': docs,
|
||||||
'docs_voiture': docs_voiture,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@view_config(route_name='doc_edit', renderer='../templates/doc_edit.pt', permission='view')
|
@view_config(route_name='doc_edit', renderer='../templates/doc_edit.pt', permission='view')
|
||||||
@@ -182,6 +96,8 @@ def doc_edit(request):
|
|||||||
url = request.route_url('doc_edit',doc_id=doc_id)
|
url = request.route_url('doc_edit',doc_id=doc_id)
|
||||||
|
|
||||||
message = ""
|
message = ""
|
||||||
|
themes = get_blog_themes(request)
|
||||||
|
|
||||||
if doc_id == '0':
|
if doc_id == '0':
|
||||||
titre = "Nouveau doc"
|
titre = "Nouveau doc"
|
||||||
intitule = ""
|
intitule = ""
|
||||||
@@ -222,7 +138,7 @@ def doc_edit(request):
|
|||||||
'intitule': intitule,
|
'intitule': intitule,
|
||||||
'texte': texte,
|
'texte': texte,
|
||||||
'theme': theme,
|
'theme': theme,
|
||||||
'themes': ["MAISON","FINANCE","VOITURE"],
|
'themes': themes,
|
||||||
}
|
}
|
||||||
|
|
||||||
@view_config(route_name='doc_view', renderer='../templates/doc_view.pt', permission='view')
|
@view_config(route_name='doc_view', renderer='../templates/doc_view.pt', permission='view')
|
||||||
|
|||||||
@@ -190,10 +190,7 @@ def logout(request):
|
|||||||
request.session.invalidate()
|
request.session.invalidate()
|
||||||
headers = forget(request)
|
headers = forget(request)
|
||||||
request.session.flash(u"Vous avez bien été déconnecté.")
|
request.session.flash(u"Vous avez bien été déconnecté.")
|
||||||
return HTTPFound(location=request.route_url('login', login=''),
|
return HTTPFound(location=request.route_url('home'), headers=headers)
|
||||||
headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='user_edit', renderer='../templates/members/user_edit.pt', permission='manage')
|
@view_config(route_name='user_edit', renderer='../templates/members/user_edit.pt', permission='manage')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pyramid.includes =
|
|||||||
pyramid_mailer
|
pyramid_mailer
|
||||||
pyramid_tm
|
pyramid_tm
|
||||||
|
|
||||||
sqlalchemy.url = mysql://phuoc:phuoc!@localhost/bd_mesavoirs?charset=utf8
|
sqlalchemy.url = mysql://root:phuoc!@localhost/bd_mesavoirs?charset=utf8
|
||||||
|
|
||||||
caotek_mesavoirs.admin_email = cao.thien-phuoc@orange.fr
|
caotek_mesavoirs.admin_email = cao.thien-phuoc@orange.fr
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ mail.port = 25
|
|||||||
[server:main]
|
[server:main]
|
||||||
use = egg:waitress#main
|
use = egg:waitress#main
|
||||||
host = 0.0.0.0
|
host = 0.0.0.0
|
||||||
port = 6543
|
port = 9080
|
||||||
|
|
||||||
###
|
###
|
||||||
# logging configuration
|
# logging configuration
|
||||||
|
|||||||