Affichage graph des données

This commit is contained in:
Jérôme Delacotte
2025-05-07 16:45:28 +02:00
parent 7f778867c4
commit 5861697489
5 changed files with 221 additions and 109 deletions

View File

@@ -7,4 +7,4 @@ matplotlib
Flask==2.2.3
Werkzeug==2.2.3
joblib==1.4.2
pyarrow

View File

@@ -9,19 +9,22 @@ from io import TextIOWrapper
app = Flask(__name__)
FILES_DIR = '/mnt/external'
FREQTRADE_USERDATA_DIR = '/mnt/external'
@app.route('/')
def home():
# Liste les fichiers dans le répertoire monté
files = os.listdir('/mnt/external')
files = os.listdir(FREQTRADE_USERDATA_DIR + "/backtest_results")
# Filtre pour obtenir uniquement les fichiers (pas les dossiers)
files = [f for f in files if os.path.isfile(os.path.join('/mnt/external', f))]
files = [f for f in files if os.path.isfile(os.path.join(FREQTRADE_USERDATA_DIR + "/backtest_results", f))]
files2 = os.listdir(FREQTRADE_USERDATA_DIR + "/data/binance")
files2 = [f for f in files2 if os.path.isfile(os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance", f))]
# Retourne le template avec la liste des fichiers
return render_template('index.html', files=files)
return render_template('index.html', files=files, files2=files2)
@app.route('/process', methods=['POST'])
@@ -32,7 +35,7 @@ def process():
@app.route('/read_json/<path:filename>')
def read_json(filename):
full_path = os.path.join(FILES_DIR, filename)
full_path = os.path.join(FREQTRADE_USERDATA_DIR + "/backtest_results", filename)
if filename.endswith('.json'):
with open(full_path) as f:
@@ -66,16 +69,28 @@ def read_json(filename):
try:
data = joblib.load(f)
if isinstance(data, pd.DataFrame):
return data.to_json(orient='split'), 200, {'Content-Type': 'application/json'}
if isinstance(data, dict):
df = pd.DataFrame.from_dict(data)
return df.to_json(orient='split'), 200, {'Content-Type': 'application/json'}
if isinstance(data, list):
print("dataframe")
zip_contents[name] = data.to_csv() #orient='split'), 200, {'Content-Type': 'application/json'}
elif isinstance(data, dict):
# On suppose quil y a un seul modèle/clé au premier niveau
outer_key = list(data.keys())[0]
inner_dict = data[outer_key]
if isinstance(inner_dict, dict):
# On suppose quil y a une seule paire (ex: 'BTC/USDT')
inner_key = list(inner_dict.keys())[0]
df = inner_dict[inner_key]
print(df)
if isinstance(df, pd.DataFrame):
zip_contents[name] = df.to_html() #json(orient='split'), 200, {'Content-Type': 'application/json'}
elif isinstance(data, list):
print('list')
df = pd.DataFrame(data)
return df.to_json(orient='split'), 200, {'Content-Type': 'application/json'}
return json.dumps({"error": f"Type {type(data)} non géré."}), 200
zip_contents[name] = df.to_html() #orient='split'), 200, {'Content-Type': 'application/json'}
else:
zip_contents[name] = json.dumps({"error": f"Type {type(data)} non géré."}), 200
except Exception as e:
return json.dumps({"error": str(e)}), 500
zip_contents[name] = json.dumps({"error": str(e)}), 500
return json.dumps(zip_contents)
except Exception as e:
return json.dumps({"error": str(e)}), 500
@@ -83,5 +98,18 @@ def read_json(filename):
return json.dumps({"error": "Fichier non pris en charge"}), 400
@app.route('/read_feather/<path:filename>')
def read_feather(filename):
path = os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance/", filename)
try:
print(path)
df = pd.read_feather(path)
print(df)
return df.to_json(orient="records")
except Exception as e:
print(e)
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)

87
src/static/css/style.css Normal file
View File

@@ -0,0 +1,87 @@
/* Style de la page */
body {
font-family: Arial, sans-serif;
display: flex;
}
/* Colonne gauche pour les fichiers */
.file-list {
width: 200px;
padding: 10px;
border-right: 1px solid #ccc;
}
/* Colonne pour le graphique */
.graph-container {
flex-grow: 1;
padding: 10px;
}
/* Liste des fichiers */
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 5px;
border-bottom: 1px solid #ddd;
}
li:hover {
background-color: #f0f0f0;
}
.file-list li {
cursor: pointer;
margin: 5px 0;
}
.content {
flex-grow: 1;
padding: 10px;
}
.tab {
display: none;
}
.tab.active {
display: block;
}
.tab-header {
font-weight: bold;
margin-top: 20px;
}
pre {
background: #f5f5f5;
padding: 10px;
overflow-x: auto;
}
#json-tabs {
display: flex;
flex-direction: column;
}
#tab-buttons {
list-style: none;
padding: 0;
display: flex;
gap: 0.5rem;
}
#tab-buttons li {
display: inline;
}
#tab-buttons button {
padding: 0.4rem 1rem;
cursor: pointer;
}
.tab-content {
border: 1px solid #ccc;
padding: 1rem;
background: #f9f9f9;
margin-top: 1rem;
white-space: pre-wrap;
}

View File

@@ -78,3 +78,82 @@ function graph() {
// Utiliser les options pour afficher le graphique
chart.setOption(option);
}
function loadFeather(filename) {
fetch(`/read_feather/${filename}`)
.then(response => response.json())
.then(data => {
// Table
const table = document.getElementById('data-table');
if (data.length > 0) {
let header = '<tr>' + Object.keys(data[0]).map(k => `<th>${k}</th>`).join('') + '</tr>';
let rows = data.map(row => '<tr>' + Object.values(row).map(v => `<td>${v}</td>`).join('') + '</tr>');
table.innerHTML = header + rows.join('');
}
// ECharts (Close price over time)
const chart = echarts.init(document.getElementById('chart'));
// const option = {
// xAxis: {
// type: 'category',
// data: data.map(d => d.date)
// },
// yAxis: {
// type: 'value'
// },
// series: [{
// type: 'line',
// name: 'Close',
// data: data.map(d => d.close)
// }]
// };
// specify chart configuration item and data
var option = {
title: {
text: filename
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
dataView: {show: true, readOnly: false},
restore: {show: true},
saveAsImage: {show: true}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
}
},
// legend: {
// data:[]
// },
xAxis: {
type: 'category',
data: data.map(d => {
const date = new Date(d.date);
return date.toLocaleDateString('fr-FR'); // ex : 07/05/2025
})
},
yAxis: {
type: 'value'
},
series: [{
type: 'line',
name: 'Close',
data: data.map(d => d.close)
}]
};
chart.setOption(option);
});
}

View File

@@ -6,96 +6,7 @@
<title>Statistiques Freqtrade</title>
<script src="{{ url_for('static', filename='js/echarts.js') }}"></script>
<script src="{{ url_for('static', filename='js/functions.js') }}"></script>
<style>
/* Style de la page */
body {
font-family: Arial, sans-serif;
display: flex;
}
/* Colonne gauche pour les fichiers */
.file-list {
width: 200px;
padding: 10px;
border-right: 1px solid #ccc;
}
/* Colonne pour le graphique */
.graph-container {
flex-grow: 1;
padding: 10px;
}
/* Liste des fichiers */
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 5px;
border-bottom: 1px solid #ddd;
}
li:hover {
background-color: #f0f0f0;
}
.file-list li {
cursor: pointer;
margin: 5px 0;
}
.content {
flex-grow: 1;
padding: 10px;
}
.tab {
display: none;
}
.tab.active {
display: block;
}
.tab-header {
font-weight: bold;
margin-top: 20px;
}
pre {
background: #f5f5f5;
padding: 10px;
overflow-x: auto;
}
#json-tabs {
display: flex;
flex-direction: column;
}
#tab-buttons {
list-style: none;
padding: 0;
display: flex;
gap: 0.5rem;
}
#tab-buttons li {
display: inline;
}
#tab-buttons button {
padding: 0.4rem 1rem;
cursor: pointer;
}
.tab-content {
border: 1px solid #ccc;
padding: 1rem;
background: #f9f9f9;
margin-top: 1rem;
white-space: pre-wrap;
}
</style>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"/>
</head>
<body>
<!-- Colonne gauche avec les fichiers -->
@@ -105,6 +16,10 @@
{% for file in files %}
<li onclick="loadJson('{{ file }}')">{{ file }}</li>
{% endfor %}
{% for file in files2 %}
<li onclick="loadFeather('{{ file }}')">{{ file }}</li>
{% endfor %}
</ul>
</div>
<div class="content">
@@ -114,16 +29,19 @@
</div>
</div>
<div id="chart" style="width: 100%; height: 1024px;"></div>
<h3>Données</h3>
<table border="1" id="data-table"></table>
<!--<div id="data-table" style="margin-left: 220px; padding: 20px;"></div>-->
<!-- Colonne droite avec le graphique (remplacez avec votre graphique)
<div class="graph-container">
<h3>Graphique</h3>
<div id="chart" style="width: 600px; height: 400px;"></div>
</div>
-->
<form action="/process" method="post">
<input type="text" name="data" placeholder="Entrez des données">
<button type="submit">Envoyer</button>
</form>
</body>
</html>