Merge pull request #8 from tpokorra/TP-202101-graphs
display graphs for exchange rates
This commit was merged in pull request #8.
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
/* https://github.com/nathancahill/skeleton-tabs */
|
||||||
|
ul.tab-nav {
|
||||||
|
list-style: none;
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tab-nav li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tab-nav li a.button {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tab-nav li a.active.button {
|
||||||
|
border-bottom: 0.175em solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .tab-pane {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content .tab-pane.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/* https://github.com/nathancahill/skeleton-tabs */
|
||||||
|
(function() {
|
||||||
|
function main() {
|
||||||
|
var tabButtons = [].slice.call(document.querySelectorAll('ul.tab-nav li a.button'));
|
||||||
|
|
||||||
|
tabButtons.map(function(button) {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
document.querySelector('li a.active.button').classList.remove('active');
|
||||||
|
button.classList.add('active');
|
||||||
|
|
||||||
|
document.querySelector('.tab-pane.active').classList.remove('active');
|
||||||
|
document.querySelector(button.getAttribute('href')).classList.add('active');
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState !== 'loading') {
|
||||||
|
main();
|
||||||
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', main);
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'css/topnav.css' %}">
|
<link rel="stylesheet" href="{% static 'css/topnav.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'css/accordion.css' %}">
|
<link rel="stylesheet" href="{% static 'css/accordion.css' %}">
|
||||||
|
<link rel="stylesheet" href="{% static 'css/skeleton-tabs.css' %}">
|
||||||
|
<script src="{% static 'js/skeleton-tabs.js' %}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
from django.db import connection
|
||||||
|
import datetime
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from io import StringIO
|
||||||
|
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
import matplotlib.ticker as plticker
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
class Graph:
|
||||||
|
|
||||||
|
def graph_days(self, Crypto, Fiat, DayDiff):
|
||||||
|
|
||||||
|
x = []
|
||||||
|
y = []
|
||||||
|
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
sql = """SELECT date(datetime_valid), rate FROM
|
||||||
|
(select date(datetime_valid) as day, max(datetime_valid) as last
|
||||||
|
from exchangerate WHERE crypto_currency = %s AND fiat_currency = %s
|
||||||
|
AND datetime_valid >= %s
|
||||||
|
GROUP BY day
|
||||||
|
ORDER BY datetime_valid DESC) AS a
|
||||||
|
JOIN exchangerate AS b ON a.last = b.datetime_valid
|
||||||
|
AND crypto_currency = %s AND fiat_currency = %s
|
||||||
|
ORDER BY datetime_valid ASC"""
|
||||||
|
startDate = datetime.datetime.today().replace(hour=0, minute=0, second=0, microsecond=0) - datetime.timedelta(days=int(DayDiff))
|
||||||
|
cursor.execute(sql, [Crypto, Fiat, startDate, Crypto, Fiat])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
for row in rows:
|
||||||
|
x.append(datetime.datetime.strptime(row[0], '%Y-%m-%d'))
|
||||||
|
y.append(row[1])
|
||||||
|
|
||||||
|
if len(x) == 0:
|
||||||
|
raise Exception("no data for this time range in the database")
|
||||||
|
|
||||||
|
fig_size = plt.rcParams["figure.figsize"]
|
||||||
|
fig_size[0] = 5
|
||||||
|
fig_size[1] = 4
|
||||||
|
plt.rcParams["figure.figsize"] = fig_size
|
||||||
|
|
||||||
|
fig = Figure()
|
||||||
|
ax = fig.add_subplot(1, 1, 1)
|
||||||
|
|
||||||
|
ax.plot(x, y, color='green', linestyle='dashed', linewidth = 2,
|
||||||
|
marker='o', markerfacecolor='blue', markersize=2)
|
||||||
|
|
||||||
|
loc = plticker.MultipleLocator(base=(len(x)/4.0))
|
||||||
|
ax.xaxis.set_major_locator(loc)
|
||||||
|
|
||||||
|
ax.set_xlabel("time")
|
||||||
|
ax.set_ylabel(Fiat)
|
||||||
|
ax.set_title(('%s in %s' % (Crypto, Fiat)))
|
||||||
|
|
||||||
|
response = HttpResponse(content_type = 'image/png')
|
||||||
|
canvas = FigureCanvasAgg(fig)
|
||||||
|
canvas.print_png(response)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def graph_hours(self, Crypto, Fiat, HourDiff):
|
||||||
|
|
||||||
|
x = []
|
||||||
|
y = []
|
||||||
|
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
sql = """SELECT datetime_valid, rate FROM exchangerate
|
||||||
|
WHERE crypto_currency = %s AND fiat_currency = %s
|
||||||
|
AND datetime_valid >= %s
|
||||||
|
ORDER BY datetime_valid ASC"""
|
||||||
|
startDate = datetime.datetime.today() - datetime.timedelta(hours=int(HourDiff))
|
||||||
|
cursor.execute(sql, [Crypto, Fiat, startDate])
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
for row in rows:
|
||||||
|
x.append(row[0])
|
||||||
|
y.append(row[1])
|
||||||
|
|
||||||
|
if len(x) == 0:
|
||||||
|
raise Exception("no data for this time range in the database")
|
||||||
|
|
||||||
|
fig = Figure()
|
||||||
|
ax = fig.add_subplot(1, 1, 1)
|
||||||
|
|
||||||
|
ax.plot(x, y, color='green', linestyle='dashed', linewidth = 2,
|
||||||
|
marker='o', markerfacecolor='blue', markersize=2)
|
||||||
|
|
||||||
|
loc = plticker.MultipleLocator(base=(len(x)/5.0))
|
||||||
|
ax.xaxis.set_major_locator(loc)
|
||||||
|
|
||||||
|
ax.set_xlabel("time")
|
||||||
|
ax.set_ylabel(Fiat)
|
||||||
|
ax.set_title(('%s in %s' % (Crypto, Fiat)))
|
||||||
|
|
||||||
|
response = HttpResponse(content_type = 'image/png')
|
||||||
|
canvas = FigureCanvasAgg(fig)
|
||||||
|
canvas.print_png(response)
|
||||||
|
return response
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="form-box">
|
<div class="form-box">
|
||||||
<h2>Monitor</h2>
|
<h2>Monitor</h2>
|
||||||
|
<a href="/monitor" class="button button-primary">Refresh</a><br/>
|
||||||
<p>Hint: these numbers are not very accurate.</p>
|
<p>Hint: these numbers are not very accurate.</p>
|
||||||
|
|
||||||
{% for c in cryptos %}
|
{% for c in cryptos %}
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
{% if c.bought_tax_free %}
|
{% if c.bought_tax_free %}
|
||||||
We can sell without paying taxes: {{ c.bought_tax_free|floatformat:3 }} {{ c.crypto }} for {{ c.value_tax_free|floatformat:2 }} EUR<br/>
|
We can sell without paying taxes: {{ c.bought_tax_free|floatformat:3 }} {{ c.crypto }} for {{ c.value_tax_free|floatformat:2 }} EUR<br/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<br/><a href="/transactions/show?crypto={{ c.crypto }}">My transactions</a><br/>
|
||||||
|
|
||||||
{% if c.rates %}
|
{% if c.rates %}
|
||||||
<table>
|
<table>
|
||||||
@@ -44,9 +46,55 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ul class="tab-nav">
|
||||||
|
<li>
|
||||||
|
<a class="button active" href="#h48{{ c.crypto }}">48 hours</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" href="#d3{{ c.crypto }}">3 days</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" href="#w1{{ c.crypto }}">1 week</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" href="#m1{{ c.crypto }}">1 month</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" href="#m6{{ c.crypto }}">6 months</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" href="#y1{{ c.crypto }}">1 year</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="h48{{ c.crypto }}">
|
||||||
|
48 hours
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_hours=48" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="d3{{ c.crypto }}">
|
||||||
|
3 days
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_days=3" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="w1{{ c.crypto }}">
|
||||||
|
1 week
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_days=7" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="m1{{ c.crypto }}">
|
||||||
|
1 month
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_days=30" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="m6{{ c.crypto }}">
|
||||||
|
6 months
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_days=180" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="y1{{ c.crypto }}">
|
||||||
|
1 year
|
||||||
|
<img src="/graph?crypto={{ c.crypto }}&fiat=EUR&number_of_days=360" loading="lazy">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<br/><a href="/transactions/show?crypto={{ c.crypto }}">My transactions</a><br/>
|
|
||||||
<br/>
|
<br/>
|
||||||
Google: <br/>
|
Google: <br/>
|
||||||
<a href='https://www.google.com/search?channel=crow2&client=firefox-b-d&q={{ c.crypto }}+in+eur%3D' target='_blank'>{{ c.crypto }} in EUR</a><br/>
|
<a href='https://www.google.com/search?channel=crow2&client=firefox-b-d&q={{ c.crypto }}+in+eur%3D' target='_blank'>{{ c.crypto }} in EUR</a><br/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from apps.transactions.models import Transaction
|
from apps.transactions.models import Transaction
|
||||||
from apps.rates.models import ExchangeRate
|
from apps.rates.models import ExchangeRate
|
||||||
from apps.monitor.calc import Calc
|
from apps.monitor.calc import Calc
|
||||||
|
from apps.monitor.graph import Graph
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def monitor(request):
|
def monitor(request):
|
||||||
@@ -20,3 +21,17 @@ def monitor(request):
|
|||||||
cryptos.append({"crypto": crypto, "rateEUR": rateEUR, "rateUSD": rateUSD, **out2})
|
cryptos.append({"crypto": crypto, "rateEUR": rateEUR, "rateUSD": rateUSD, **out2})
|
||||||
|
|
||||||
return render(request,"monitor.html",{'cryptos':cryptos, 'total_tax_free': total_tax_free, 'total_investment': total_investment, 'current_value': current_value})
|
return render(request,"monitor.html",{'cryptos':cryptos, 'total_tax_free': total_tax_free, 'total_investment': total_investment, 'current_value': current_value})
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def graph(request):
|
||||||
|
if not 'crypto' in request.GET:
|
||||||
|
return
|
||||||
|
if not 'fiat' in request.GET:
|
||||||
|
return
|
||||||
|
Crypto = request.GET['crypto']
|
||||||
|
Fiat = request.GET['fiat']
|
||||||
|
|
||||||
|
if 'number_of_days' in request.GET:
|
||||||
|
return Graph().graph_days(Crypto, Fiat, request.GET['number_of_days'])
|
||||||
|
if 'number_of_hours' in request.GET:
|
||||||
|
return Graph().graph_hours(Crypto, Fiat, request.GET['number_of_hours'])
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
django
|
django
|
||||||
django-registration
|
django-registration
|
||||||
|
matplotlib
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ urlpatterns = [
|
|||||||
path('', core_views.home),
|
path('', core_views.home),
|
||||||
path('home/', core_views.home),
|
path('home/', core_views.home),
|
||||||
path('monitor/', monitor_views.monitor),
|
path('monitor/', monitor_views.monitor),
|
||||||
|
path('graph/', monitor_views.graph),
|
||||||
path('transactions/add', tr_views.add),
|
path('transactions/add', tr_views.add),
|
||||||
path('transactions/show', tr_views.show),
|
path('transactions/show', tr_views.show),
|
||||||
path('transactions/edit/<int:id>', tr_views.edit),
|
path('transactions/edit/<int:id>', tr_views.edit),
|
||||||
|
|||||||
Reference in New Issue
Block a user