Affichage graph des données / sélection des indicateurs
This commit is contained in:
@@ -6,7 +6,6 @@ docker build -t flask-web-app .
|
|||||||
|
|
||||||
## Lancement
|
## Lancement
|
||||||
|
|
||||||
|
docker run -it -p 5000:5000 -v $(pwd)/src/:/src -v /home/jerome/Perso/freqtradeDocker/user_data/:/mnt/external flask-web-app bash
|
||||||
docker run -it -p 5000:5000 -v $(pwd)/src/:/src -v /home/jerome/Perso/freqtradeDocker/user_data/backtest_results:/mnt/external flask-web-app bash
|
|
||||||
|
|
||||||
puis : python3 app.py
|
puis : python3 app.py
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ Flask==2.2.3
|
|||||||
Werkzeug==2.2.3
|
Werkzeug==2.2.3
|
||||||
joblib==1.4.2
|
joblib==1.4.2
|
||||||
pyarrow
|
pyarrow
|
||||||
|
pandas-ta
|
||||||
|
|||||||
55
src/app.py
55
src/app.py
@@ -1,4 +1,4 @@
|
|||||||
from flask import Flask, jsonify, abort, render_template, send_from_directory
|
from flask import Flask, jsonify, abort, render_template, send_from_directory,request
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import json
|
import json
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -102,14 +102,59 @@ def read_json(filename):
|
|||||||
def read_feather(filename):
|
def read_feather(filename):
|
||||||
path = os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance/", filename)
|
path = os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance/", filename)
|
||||||
try:
|
try:
|
||||||
print(path)
|
dataframe = pd.read_feather(path)
|
||||||
df = pd.read_feather(path)
|
# dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200)
|
||||||
print(df)
|
# dataframe['min12'] = talib.MIN(dataframe['close'], timeperiod=12)
|
||||||
return df.to_json(orient="records")
|
#
|
||||||
|
# dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50)
|
||||||
|
# dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
|
||||||
|
# dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
|
||||||
|
|
||||||
|
return dataframe.to_json(orient="records")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/get_chart_data')
|
||||||
|
def get_chart_data():
|
||||||
|
filename = request.args.get('filename', '')
|
||||||
|
path = os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance/", filename)
|
||||||
|
print(path)
|
||||||
|
indicators = request.args.get('indicators', '').split(',')
|
||||||
|
df = pd.read_feather(path)
|
||||||
|
print(df)
|
||||||
|
|
||||||
|
# # Calculs conditionnels
|
||||||
|
# if 'sma' in indicators:
|
||||||
|
# df['sma'] = df['close'].rolling(window=20).mean()
|
||||||
|
# if 'rsi' in indicators:
|
||||||
|
# delta = df['close'].diff()
|
||||||
|
# gain = delta.where(delta > 0, 0)
|
||||||
|
# loss = -delta.where(delta < 0, 0)
|
||||||
|
# avg_gain = gain.rolling(14).mean()
|
||||||
|
# avg_loss = loss.rolling(14).mean()
|
||||||
|
# rs = avg_gain / avg_loss
|
||||||
|
# df['rsi'] = 100 - (100 / (1 + rs))
|
||||||
|
# if 'bollinger' in indicators:
|
||||||
|
# sma = df['close'].rolling(window=20).mean()
|
||||||
|
# std = df['close'].rolling(window=20).std()
|
||||||
|
# df['bb_upper'] = sma + 2 * std
|
||||||
|
# df['bb_lower'] = sma - 2 * std
|
||||||
|
#
|
||||||
|
# df = df.dropna()
|
||||||
|
|
||||||
|
# Simplifier les données pour le JSON
|
||||||
|
# chart_data = {
|
||||||
|
# 'date': df['date'].astype(str).tolist(),
|
||||||
|
# 'close': df['close'].tolist(),
|
||||||
|
# 'sma': df.get('sma', pd.Series()).tolist(),
|
||||||
|
# 'rsi': df.get('rsi', pd.Series()).tolist(),
|
||||||
|
# 'bb_upper': df.get('bb_upper', pd.Series()).tolist(),
|
||||||
|
# 'bb_lower': df.get('bb_lower', pd.Series()).tolist(),
|
||||||
|
# }
|
||||||
|
|
||||||
|
return df.to_json(orient="records") #jsonify(chart_data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||||
|
|||||||
@@ -79,18 +79,31 @@ function graph() {
|
|||||||
chart.setOption(option);
|
chart.setOption(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFeather(filename) {
|
function renderChart(data, filename, create_columns) {
|
||||||
fetch(`/read_feather/${filename}`)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// Table
|
// Table
|
||||||
const table = document.getElementById('data-table');
|
// const table = document.getElementById('data-table');
|
||||||
if (data.length > 0) {
|
// if (data.length > 0) {
|
||||||
let header = '<tr>' + Object.keys(data[0]).map(k => `<th>${k}</th>`).join('') + '</tr>';
|
// 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>');
|
// let rows = data.map(row => '<tr>' + Object.values(row).map(v => `<td>${v}</td>`).join('') + '</tr>');
|
||||||
table.innerHTML = header + rows.join('');
|
// table.innerHTML = header + rows.join('');
|
||||||
|
// }
|
||||||
|
const cols = Object.keys(data[0])
|
||||||
|
if (create_columns === true) {
|
||||||
|
string = "<ul class='indicators'>" + Object.keys(data[0]).map(cols => `<li><label><input id="${cols}" type="checkbox" value="${cols}" onchange="toggleIndicator(this)">${cols}</label></li>`).join('') + "</ul>"
|
||||||
|
const indicators = document.getElementById('indicators');
|
||||||
|
indicators.innerHTML = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// const label = document.createElement('label');
|
||||||
|
// label.innerHTML = `<input type="checkbox" value="${col}"> ${col}<br>`;
|
||||||
|
// indicators.appendChild(label);
|
||||||
|
|
||||||
|
let totalPoints = data.length;
|
||||||
|
let visiblePoints = 100;
|
||||||
|
let startPercent = ((totalPoints - visiblePoints) / totalPoints) * 100;
|
||||||
|
|
||||||
// ECharts (Close price over time)
|
// ECharts (Close price over time)
|
||||||
const chart = echarts.init(document.getElementById('chart'));
|
const chart = echarts.init(document.getElementById('chart'));
|
||||||
// const option = {
|
// const option = {
|
||||||
@@ -108,6 +121,45 @@ function loadFeather(filename) {
|
|||||||
// }]
|
// }]
|
||||||
// };
|
// };
|
||||||
// specify chart configuration item and data
|
// specify chart configuration item and data
|
||||||
|
|
||||||
|
const series = [{
|
||||||
|
type: 'line',
|
||||||
|
name: 'Close',
|
||||||
|
data: data.map(d => d.close)
|
||||||
|
}]
|
||||||
|
// df_ohlc = data
|
||||||
|
// df_ohlc['date'] = pd.to_datetime(data['date']).dt.strftime('%Y-%m-%d')
|
||||||
|
// df_ohlc = data[['date', 'open', 'close', 'low', 'high']]
|
||||||
|
// series.push({
|
||||||
|
// type: 'candlestick',
|
||||||
|
// data: {
|
||||||
|
// 'dates': df_ohlc['date'].tolist(),
|
||||||
|
// 'ohlc': df_ohlc[['open', 'close', 'low', 'high']].values.tolist()
|
||||||
|
// },
|
||||||
|
// itemStyle: {
|
||||||
|
// color: '#ec0000', // bougie haussière (fermée plus haut que ouverte)
|
||||||
|
// color0: '#00da3c', // bougie baissière
|
||||||
|
// borderColor: '#8A0000',
|
||||||
|
// borderColor0: '#008F28'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
|
for (var key in cols) {
|
||||||
|
var value = cols[key];
|
||||||
|
element=document.getElementById(value)
|
||||||
|
if (element) {
|
||||||
|
if (element.checked) {
|
||||||
|
series.push({
|
||||||
|
name: value,
|
||||||
|
type: 'line',
|
||||||
|
data: data.map(d => d[value]),
|
||||||
|
smooth: true,
|
||||||
|
lineStyle: { color: stringToColor(value) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
var option = {
|
var option = {
|
||||||
title: {
|
title: {
|
||||||
text: filename
|
text: filename
|
||||||
@@ -134,9 +186,21 @@ function loadFeather(filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// legend: {
|
dataZoom: [
|
||||||
// data:[]
|
{
|
||||||
// },
|
type: 'slider', // slider visible en bas
|
||||||
|
start: startPercent,
|
||||||
|
end: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'inside', // zoom avec la molette de la souris
|
||||||
|
start: startPercent,
|
||||||
|
end: 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
legend: {
|
||||||
|
data: cols, // Affiche les noms de chaque série avec leur couleur
|
||||||
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
data: data.map(d => {
|
data: data.map(d => {
|
||||||
@@ -145,15 +209,65 @@ function loadFeather(filename) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value'
|
type: 'value',
|
||||||
|
min: 'dataMin', // <-- commence à la plus petite valeur
|
||||||
|
max: 'dataMax' // <-- adapte aussi le maximum
|
||||||
},
|
},
|
||||||
series: [{
|
series: series
|
||||||
type: 'line',
|
}
|
||||||
name: 'Close',
|
|
||||||
data: data.map(d => d.close)
|
chart.setOption(option)
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
chart.setOption(option);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadFeather(filename) {
|
||||||
|
const element = document.getElementById('current_file_name');
|
||||||
|
element.value = filename
|
||||||
|
fetch(`/read_feather/${filename}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => renderChart(data, filename, true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let selectedIndicators = new Set();
|
||||||
|
|
||||||
|
function toggleIndicator(checkbox) {
|
||||||
|
const indicator = checkbox.value;
|
||||||
|
if (checkbox.checked) {
|
||||||
|
selectedIndicators.add(indicator);
|
||||||
|
} else {
|
||||||
|
selectedIndicators.delete(indicator);
|
||||||
|
}
|
||||||
|
loadChartWithIndicators();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadChartWithIndicators() {
|
||||||
|
const element = document.getElementById('current_file_name');
|
||||||
|
let filename = element.value
|
||||||
|
const indicators = Array.from(selectedIndicators).join(',');
|
||||||
|
fetch(`/get_chart_data?filename=${filename}&indicators=${indicators}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => renderChart(data, filename, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
//function createListeners() {
|
||||||
|
// // Écouteurs d'événement
|
||||||
|
// document.querySelectorAll('input[type=checkbox]').forEach(cb => {
|
||||||
|
// cb.addEventListener('change', () => {
|
||||||
|
// chart.setOption({ series: getSeries() });
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
|
function stringToColor(str) {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertir le hash en une teinte HSL (0-360°)
|
||||||
|
const hue = hash % 360;
|
||||||
|
// Saturation et luminosité réglées pour contraste
|
||||||
|
return `hsl(${hue}, 70%, 50%)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="indicators">
|
||||||
|
<label><input id="smaCheckbox" type="checkbox" value="sma" onchange="toggleIndicator(this)"> SMA</label>
|
||||||
|
<label><input id="rsiCheckbox" type="checkbox" value="rsi" onchange="toggleIndicator(this)"> RSI</label>
|
||||||
|
<label><input id="bbCheckbox" type="checkbox" value="bollinger" onchange="toggleIndicator(this)"> Bollinger</label>
|
||||||
|
</div>
|
||||||
<div id="chart" style="width: 100%; height: 1024px;"></div>
|
<div id="chart" style="width: 100%; height: 1024px;"></div>
|
||||||
<h3>Données</h3>
|
|
||||||
<table border="1" id="data-table"></table>
|
<table border="1" id="data-table"></table>
|
||||||
|
|
||||||
<!--<div id="data-table" style="margin-left: 220px; padding: 20px;"></div>-->
|
<!--<div id="data-table" style="margin-left: 220px; padding: 20px;"></div>-->
|
||||||
|
|
||||||
|
<input id="current_file_name" hidden value="">
|
||||||
|
|
||||||
<!-- Colonne droite avec le graphique (remplacez avec votre graphique)
|
<!-- Colonne droite avec le graphique (remplacez avec votre graphique)
|
||||||
<div class="graph-container">
|
<div class="graph-container">
|
||||||
|
|||||||
Reference in New Issue
Block a user