travail avec le contenu des backtests et amélioration graphs avec puces
This commit is contained in:
27
src/app.py
27
src/app.py
@@ -18,10 +18,10 @@ def home():
|
|||||||
files = os.listdir(FREQTRADE_USERDATA_DIR + "/backtest_results")
|
files = os.listdir(FREQTRADE_USERDATA_DIR + "/backtest_results")
|
||||||
|
|
||||||
# Filtre pour obtenir uniquement les fichiers (pas les dossiers)
|
# Filtre pour obtenir uniquement les fichiers (pas les dossiers)
|
||||||
files = [f for f in files if os.path.isfile(os.path.join(FREQTRADE_USERDATA_DIR + "/backtest_results", f))]
|
files = [f for f in files if os.path.isfile(os.path.join(FREQTRADE_USERDATA_DIR + "/backtest_results", f)) and f.lower().endswith('.zip')]
|
||||||
|
|
||||||
files2 = os.listdir(FREQTRADE_USERDATA_DIR + "/data/binance")
|
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))]
|
files2 = [f for f in files2 if os.path.isfile(os.path.join(FREQTRADE_USERDATA_DIR + "/data/binance", f)) and f.lower().endswith('.feather')]
|
||||||
|
|
||||||
# Retourne le template avec la liste des fichiers
|
# Retourne le template avec la liste des fichiers
|
||||||
return render_template('index.html', files=files, files2=files2)
|
return render_template('index.html', files=files, files2=files2)
|
||||||
@@ -63,30 +63,41 @@ def read_json(filename):
|
|||||||
for name in z.namelist():
|
for name in z.namelist():
|
||||||
if name.endswith('.json'):
|
if name.endswith('.json'):
|
||||||
with z.open(name) as f:
|
with z.open(name) as f:
|
||||||
|
print(f"load_json {name}")
|
||||||
zip_contents[name] = json.load(f)
|
zip_contents[name] = json.load(f)
|
||||||
|
elif name.endswith('.feather'):
|
||||||
|
with z.open(name) as f:
|
||||||
|
dataframe = pd.read_feather(f)
|
||||||
|
zip_contents[name] = dataframe.to_json(orient="records")
|
||||||
|
|
||||||
elif name.endswith('.pkl'):
|
elif name.endswith('.pkl'):
|
||||||
with z.open(name) as f:
|
with z.open(name) as f:
|
||||||
try:
|
try:
|
||||||
data = joblib.load(f)
|
data = joblib.load(f)
|
||||||
if isinstance(data, pd.DataFrame):
|
if isinstance(data, pd.DataFrame):
|
||||||
print("dataframe")
|
print(f"dataframe {name}")
|
||||||
zip_contents[name] = data.to_csv() #orient='split'), 200, {'Content-Type': 'application/json'}
|
zip_contents[name] = data.to_json(orient='records') #, 200, {'Content-Type': 'application/json'}
|
||||||
elif isinstance(data, dict):
|
elif isinstance(data, dict):
|
||||||
# On suppose qu’il y a un seul modèle/clé au premier niveau
|
# On suppose qu’il y a un seul modèle/clé au premier niveau
|
||||||
outer_key = list(data.keys())[0]
|
outer_key = list(data.keys())[0]
|
||||||
inner_dict = data[outer_key]
|
inner_dict = data[outer_key]
|
||||||
|
|
||||||
if isinstance(inner_dict, dict):
|
if isinstance(inner_dict, dict):
|
||||||
|
print(f"dict {name}")
|
||||||
# On suppose qu’il y a une seule paire (ex: 'BTC/USDT')
|
# On suppose qu’il y a une seule paire (ex: 'BTC/USDT')
|
||||||
inner_key = list(inner_dict.keys())[0]
|
inner_key = list(inner_dict.keys())[0]
|
||||||
df = inner_dict[inner_key]
|
df = inner_dict[inner_key]
|
||||||
print(df)
|
|
||||||
if isinstance(df, pd.DataFrame):
|
if isinstance(df, pd.DataFrame):
|
||||||
zip_contents[name] = df.to_html() #json(orient='split'), 200, {'Content-Type': 'application/json'}
|
type = name
|
||||||
|
# if "signals" in name:
|
||||||
|
# type = 'signals'
|
||||||
|
# elif "exited" in name:
|
||||||
|
# type = "exited"
|
||||||
|
zip_contents[type] = df.to_json(orient='records') #, 200, {'Content-Type': 'application/json'}
|
||||||
elif isinstance(data, list):
|
elif isinstance(data, list):
|
||||||
print('list')
|
print(f"list {name}")
|
||||||
df = pd.DataFrame(data)
|
df = pd.DataFrame(data)
|
||||||
zip_contents[name] = df.to_html() #orient='split'), 200, {'Content-Type': 'application/json'}
|
zip_contents[name] = df.to_json(orient='records') # , 200, {'Content-Type': 'application/json'}
|
||||||
else:
|
else:
|
||||||
zip_contents[name] = json.dumps({"error": f"Type {type(data)} non géré."}), 200
|
zip_contents[name] = json.dumps({"error": f"Type {type(data)} non géré."}), 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -10,22 +10,32 @@ function loadJson(filename) {
|
|||||||
const isMulti = typeof data === 'object' && !Array.isArray(data);
|
const isMulti = typeof data === 'object' && !Array.isArray(data);
|
||||||
|
|
||||||
if (isMulti) {
|
if (isMulti) {
|
||||||
|
let count = 0
|
||||||
Object.entries(data).forEach(([name, content], index) => {
|
Object.entries(data).forEach(([name, content], index) => {
|
||||||
const tabId = `tab-${index}`;
|
count = count + 1
|
||||||
const li = document.createElement('li');
|
if (name.includes("signals")) {
|
||||||
const btn = document.createElement('button');
|
sessionStorage.setItem('signals', content);
|
||||||
btn.textContent = name;
|
addTab('signals', count, content)
|
||||||
btn.onclick = () => showTab(tabId);
|
}
|
||||||
li.appendChild(btn);
|
if (name.includes("exited")) {
|
||||||
tabButtons.appendChild(li);
|
sessionStorage.setItem('exited', content);
|
||||||
|
addTab('exited', count, content)
|
||||||
|
}
|
||||||
|
if (name.includes("json")) {
|
||||||
|
sessionStorage.setItem('result_strategy', JSON.stringify(content.strategy));
|
||||||
|
sessionStorage.setItem('strategy_comparison', JSON.stringify(content.strategy_comparison));
|
||||||
|
addTab('result', count, JSON.stringify(content.strategy))
|
||||||
|
count = count + 1
|
||||||
|
addTab('comparaison', count, JSON.stringify(content.strategy_comparison))
|
||||||
|
}
|
||||||
|
if (name.includes("market")) {
|
||||||
|
sessionStorage.setItem('market', content);
|
||||||
|
addTab('market', count, content)
|
||||||
|
}
|
||||||
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.id = tabId;
|
|
||||||
div.className = 'tab-content';
|
|
||||||
div.style.display = index === 0 ? 'block' : 'none';
|
|
||||||
div.innerHTML = Array.isArray(content) ? renderTable(content) : `<pre>${JSON.stringify(content, null, 2)}</pre>`;
|
|
||||||
tabContents.appendChild(div);
|
|
||||||
});
|
});
|
||||||
|
// renderChart(data, '', true)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
|
div.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
|
||||||
@@ -35,6 +45,152 @@ function loadJson(filename) {
|
|||||||
.catch(err => alert("Erreur : " + err.message));
|
.catch(err => alert("Erreur : " + err.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function jsonToUl(json) {
|
||||||
|
if (typeof json !== 'object' || json === null) return document.createTextNode(json);
|
||||||
|
|
||||||
|
const ul = document.createElement('ul');
|
||||||
|
|
||||||
|
for (const key in json) {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
const value = json[key];
|
||||||
|
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
li.textContent = key;
|
||||||
|
li.appendChild(jsonToUl(value)); // recurse
|
||||||
|
} else {
|
||||||
|
li.textContent = `${key}: ${value}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ul;
|
||||||
|
}
|
||||||
|
//function jsonToTable(obj, depth = 0) {
|
||||||
|
// const table = document.createElement('table');
|
||||||
|
// table.border = 1;
|
||||||
|
//
|
||||||
|
// for (const key in obj) {
|
||||||
|
// const row = document.createElement('tr');
|
||||||
|
//
|
||||||
|
// const cellKey = document.createElement('td');
|
||||||
|
// cellKey.textContent = key;
|
||||||
|
// row.appendChild(cellKey);
|
||||||
|
//
|
||||||
|
// const cellValue = document.createElement('td');
|
||||||
|
// const value = obj[key];
|
||||||
|
//
|
||||||
|
// if (typeof value === 'object' && value !== null && depth < 4) {
|
||||||
|
// cellValue.appendChild(jsonToTable(value, depth + 1)); // recurse
|
||||||
|
// } else {
|
||||||
|
// cellValue.textContent = value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// row.appendChild(cellValue);
|
||||||
|
// table.appendChild(row);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return table;
|
||||||
|
//}
|
||||||
|
|
||||||
|
function jsonToTable(data, depth = 0) {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
// Cas: tableau d'objets
|
||||||
|
if (data.length > 0 && typeof data[0] === 'object' && !Array.isArray(data[0])) {
|
||||||
|
const table = document.createElement('table');
|
||||||
|
table.border = 1;
|
||||||
|
|
||||||
|
// En-tête
|
||||||
|
const headerRow = document.createElement('tr');
|
||||||
|
Object.keys(data[0]).forEach(key => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = key;
|
||||||
|
headerRow.appendChild(th);
|
||||||
|
});
|
||||||
|
table.appendChild(headerRow);
|
||||||
|
|
||||||
|
// Lignes de données
|
||||||
|
data.forEach(item => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
Object.values(item).forEach(value => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.textContent = (typeof value === 'object') ? JSON.stringify(value) : value;
|
||||||
|
row.appendChild(td);
|
||||||
|
});
|
||||||
|
table.appendChild(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
return table;
|
||||||
|
} else {
|
||||||
|
// Liste simple : afficher horizontalement
|
||||||
|
const table = document.createElement('table');
|
||||||
|
table.border = 1;
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
data.forEach(value => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.textContent = value;
|
||||||
|
row.appendChild(td);
|
||||||
|
});
|
||||||
|
table.appendChild(row);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (typeof data === 'object' && data !== null) {
|
||||||
|
// Cas: objet clé/valeur
|
||||||
|
const table = document.createElement('table');
|
||||||
|
table.border = 1;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
|
||||||
|
const tdKey = document.createElement('td');
|
||||||
|
tdKey.textContent = key;
|
||||||
|
row.appendChild(tdKey);
|
||||||
|
|
||||||
|
const tdValue = document.createElement('td');
|
||||||
|
const value = data[key];
|
||||||
|
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
tdValue.appendChild(jsonToTable(value, depth + 1));
|
||||||
|
} else {
|
||||||
|
tdValue.textContent = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
row.appendChild(tdValue);
|
||||||
|
table.appendChild(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return table;
|
||||||
|
} else {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.textContent = data;
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function addTab(name, index, content) {
|
||||||
|
const tabButtons = document.getElementById('tab-buttons');
|
||||||
|
const tabContents = document.getElementById('tab-contents');
|
||||||
|
const tabId = `tab-${index}`;
|
||||||
|
const li = document.createElement('li');
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.textContent = name;
|
||||||
|
btn.onclick = () => showTab(tabId);
|
||||||
|
li.appendChild(btn);
|
||||||
|
tabButtons.appendChild(li);
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.id = tabId;
|
||||||
|
div.className = 'tab-content';
|
||||||
|
div.style.display = index === 0 ? 'block' : 'none';
|
||||||
|
// div.innerHTML = Array.isArray(content) ? renderTable(content) : jsonToUl(JSON.parse(content));
|
||||||
|
ul = jsonToTable(JSON.parse(content))
|
||||||
|
div.appendChild(ul);
|
||||||
|
tabContents.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
function renderTable(rows) {
|
function renderTable(rows) {
|
||||||
if (!rows.length) return "<p>Aucune donnée</p>";
|
if (!rows.length) return "<p>Aucune donnée</p>";
|
||||||
const headers = Object.keys(rows[0]);
|
const headers = Object.keys(rows[0]);
|
||||||
@@ -88,6 +244,15 @@ function renderChart(data, filename, create_columns) {
|
|||||||
// 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('');
|
||||||
// }
|
// }
|
||||||
|
let signals = JSON.parse(sessionStorage.getItem("signals"));
|
||||||
|
let exited = JSON.parse(sessionStorage.getItem("exited"));
|
||||||
|
let market = JSON.parse(sessionStorage.getItem("market"));
|
||||||
|
let result_strategy = JSON.parse(sessionStorage.getItem("result_strategy"));
|
||||||
|
let strategy_comparison = JSON.parse(sessionStorage.getItem("strategy_comparison"));
|
||||||
|
|
||||||
|
strategy_name = strategy_comparison[0].key;
|
||||||
|
result_of_strategy = result_strategy[strategy_name]
|
||||||
|
|
||||||
const cols = Object.keys(data[0])
|
const cols = Object.keys(data[0])
|
||||||
if (create_columns === true) {
|
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>"
|
// 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>"
|
||||||
@@ -102,7 +267,6 @@ function renderChart(data, filename, create_columns) {
|
|||||||
indicators.innerHTML = string
|
indicators.innerHTML = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// const label = document.createElement('label');
|
// const label = document.createElement('label');
|
||||||
// label.innerHTML = `<input type="checkbox" value="${col}"> ${col}<br>`;
|
// label.innerHTML = `<input type="checkbox" value="${col}"> ${col}<br>`;
|
||||||
// indicators.appendChild(label);
|
// indicators.appendChild(label);
|
||||||
@@ -139,6 +303,68 @@ function renderChart(data, filename, create_columns) {
|
|||||||
// df_ohlc = data[['date', 'open', 'close', 'low', 'high']]
|
// df_ohlc = data[['date', 'open', 'close', 'low', 'high']]
|
||||||
const result = data.map(({ open, close, low, high }) => [open, close, low, high]);
|
const result = data.map(({ open, close, low, high }) => [open, close, low, high]);
|
||||||
|
|
||||||
|
marks = []
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in result_of_strategy.trades) {
|
||||||
|
var d = result_of_strategy.trades[key];
|
||||||
|
var date = new Date(d.open_date);
|
||||||
|
marks.push({
|
||||||
|
name: 'Buy',
|
||||||
|
coord: [date.toLocaleString('fr-FR', options), d.open_rate],
|
||||||
|
value: d.open_rate,
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgb(0,90,0)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for (var key2 in d.orders) {
|
||||||
|
var order = d.orders[key2]
|
||||||
|
date = new Date(order.order_filled_timestamp);
|
||||||
|
marks.push({
|
||||||
|
name: 'Buy',
|
||||||
|
coord: [date.toLocaleString('fr-FR', options), order.safe_price],
|
||||||
|
value: order.safe_price,
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgb(0,0,90)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
date = new Date(d.close_date);
|
||||||
|
marks.push({
|
||||||
|
name: 'Sell',
|
||||||
|
coord: [date.toLocaleString('fr-FR', options), d.close_rate],
|
||||||
|
value: d.close_rate,
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgb(90,0,0)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// {
|
||||||
|
// name: 'highest value',
|
||||||
|
// type: 'max',
|
||||||
|
// valueDim: 'highest'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'lowest value',
|
||||||
|
// type: 'min',
|
||||||
|
// valueDim: 'lowest'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'average value on close',
|
||||||
|
// type: 'average',
|
||||||
|
// valueDim: 'close'
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
series.push({
|
series.push({
|
||||||
type: 'candlestick',
|
type: 'candlestick',
|
||||||
data: result,
|
data: result,
|
||||||
@@ -147,10 +373,22 @@ function renderChart(data, filename, create_columns) {
|
|||||||
color0: '#00da3c', // bougie baissière
|
color0: '#00da3c', // bougie baissière
|
||||||
borderColor: '#8A0000',
|
borderColor: '#8A0000',
|
||||||
borderColor0: '#008F28'
|
borderColor0: '#008F28'
|
||||||
|
},
|
||||||
|
markPoint: {
|
||||||
|
label: {
|
||||||
|
formatter: function (param) {
|
||||||
|
return param != null ? Math.round(param.value) + '' : '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: marks,
|
||||||
|
tooltip: {
|
||||||
|
formatter: function (param) {
|
||||||
|
return param.name + '<br>' + (param.data.coord || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// console.log(result)
|
|
||||||
|
|
||||||
series.push({
|
series.push({
|
||||||
name: 'Volume',
|
name: 'Volume',
|
||||||
@@ -167,6 +405,7 @@ function renderChart(data, filename, create_columns) {
|
|||||||
},
|
},
|
||||||
data: data.map(d => d.volume)
|
data: data.map(d => d.volume)
|
||||||
})
|
})
|
||||||
|
|
||||||
for (var key in cols) {
|
for (var key in cols) {
|
||||||
var value = cols[key];
|
var value = cols[key];
|
||||||
element=document.getElementById(value)
|
element=document.getElementById(value)
|
||||||
@@ -182,6 +421,7 @@ function renderChart(data, filename, create_columns) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var option = {
|
var option = {
|
||||||
title: {
|
title: {
|
||||||
text: filename
|
text: filename
|
||||||
@@ -208,7 +448,7 @@ function renderChart(data, filename, create_columns) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataZoom: [
|
dataZoom: [
|
||||||
{
|
{
|
||||||
type: 'slider', // slider visible en bas
|
type: 'slider', // slider visible en bas
|
||||||
start: startPercent,
|
start: startPercent,
|
||||||
@@ -224,20 +464,20 @@ function renderChart(data, filename, create_columns) {
|
|||||||
data: cols, // Affiche les noms de chaque série avec leur couleur
|
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 => {
|
||||||
const date = new Date(d.date);
|
const date = new Date(d.date);
|
||||||
return date.toLocaleDateString('fr-FR'); // ex : 07/05/2025
|
return date.toLocaleString('fr-FR', options); // ex : 07/05/2025
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
data: data.map(d => {
|
data: data.map(d => {
|
||||||
const date = new Date(d.date);
|
const date = new Date(d.date);
|
||||||
return date.toLocaleDateString('fr-FR'); // ex : 07/05/2025
|
return date.toLocaleString('fr-FR', options); // ex : 07/05/2025
|
||||||
}),
|
}),
|
||||||
gridIndex: 1
|
gridIndex: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
yAxis: [{
|
yAxis: [{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
@@ -312,3 +552,13 @@ function stringToColor(str) {
|
|||||||
return `hsl(${hue}, 70%, 50%)`;
|
return `hsl(${hue}, 70%, 50%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
const dialog = document.getElementById('indicatorDialog');
|
||||||
|
document.getElementById('openIndicatorsBtn').addEventListener('click', () => {
|
||||||
|
dialog.showModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('closeIndicatorsBtn').addEventListener('click', () => {
|
||||||
|
dialog.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -12,15 +12,34 @@
|
|||||||
<!-- Colonne gauche avec les fichiers -->
|
<!-- Colonne gauche avec les fichiers -->
|
||||||
<div class="file-list">
|
<div class="file-list">
|
||||||
<h3>Fichiers :</h3>
|
<h3>Fichiers :</h3>
|
||||||
<ul>
|
<label for="json-select">Backtests :</label>
|
||||||
|
<select id="json-select" onchange="loadJson(this.value)">
|
||||||
|
<option value="">Fichier JSON</option>
|
||||||
{% for file in files %}
|
{% for file in files %}
|
||||||
<li onclick="loadJson('{{ file }}')">{{ file }}</li>
|
<option value="{{ file }}">{{ file }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<label for="feather-select">Dataframe :</label>
|
||||||
|
<select id="feather-select" onchange="loadFeather(this.value)">
|
||||||
|
<option value="">Fichier Feather</option>
|
||||||
{% for file in files2 %}
|
{% for file in files2 %}
|
||||||
<li onclick="loadFeather('{{ file }}')">{{ file }}</li>
|
<option value="{{ file }}">{{ file }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</select>
|
||||||
|
|
||||||
|
<button id="openIndicatorsBtn" style="height: 40px;">Afficher les indicateurs</button>
|
||||||
|
|
||||||
|
<dialog id="indicatorDialog">
|
||||||
|
<h3>Indicateurs</h3>
|
||||||
|
<div id="indicators">
|
||||||
|
<!-- Contenu dynamique ici -->
|
||||||
|
</div>
|
||||||
|
<button id="closeIndicatorsBtn">Fermer</button>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div id="json-tabs">
|
<div id="json-tabs">
|
||||||
@@ -29,7 +48,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="indicators"></div>
|
|
||||||
<div id="chart" style="width: 100%; height: 1024px;"></div>
|
<div id="chart" style="width: 100%; height: 1024px;"></div>
|
||||||
|
|
||||||
<table border="1" id="data-table"></table>
|
<table border="1" id="data-table"></table>
|
||||||
@@ -45,6 +63,8 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<script>init()</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user