Ajout analyse de données par réseau neuronal
This commit is contained in:
@@ -17,5 +17,5 @@ COPY . /src
|
|||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
# lancer l'application Python
|
# lancer l'application Python
|
||||||
CMD python3 app.py
|
CMD ["python", "app.py"]
|
||||||
|
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -1,14 +1,39 @@
|
|||||||
# FreqStats
|
# FreqStats
|
||||||
|
|
||||||
## Construction
|
## Adaptation de la stratégie
|
||||||
|
|
||||||
docker build -t flask-web-app .
|
### Génération du dataframe en fichier
|
||||||
|
|
||||||
|
Ajouter à la fin de populate_buy_trend :
|
||||||
|
|
||||||
|
if self.dp.runmode.value in ('backtest'):
|
||||||
|
dataframe.to_feather(f"user_data/data/binance/{metadata['pair'].replace('/', '_')}_df.feather")
|
||||||
|
|
||||||
## Lancement
|
### Lancer un backtest avec export signals
|
||||||
|
|
||||||
|
freqtrade backtesting --strategy Zeus_8_3_2_B_4_2 --config config.json --timerange 20250423-20250426 --timeframe 5m --breakdown week --enable-protections --export signals --pairs BTC/USDT
|
||||||
|
|
||||||
docker run -it -p 5000:5000 -v $(pwd)/src/:/src -v /home/jerome/Perso/freqtradeDocker/user_data/:/mnt/external flask-web-app bash
|
# Docker
|
||||||
|
## Construction
|
||||||
|
|
||||||
|
docker build -t flask-web-app .
|
||||||
|
|
||||||
|
## Lancement
|
||||||
|
|
||||||
|
docker run -it -p 5000:5000 -v $(pwd)/src/:/src -v /home/jerome/Perso/freqtradeDocker/user_data/:/mnt/external flask-web-app bash
|
||||||
|
|
||||||
|
puis : python3 app.py
|
||||||
|
|
||||||
|
# Application Web
|
||||||
|
|
||||||
|
Url : http://127.0.0.1:5000/
|
||||||
|
|
||||||
|
Choisir un backtest dans la liste
|
||||||
|
|
||||||
|
Choisir le fichier généré par le backtest par la stratégie
|
||||||
|
|
||||||
|
Cliquer sur les boutons
|
||||||
|
|
||||||
puis : python3 app.py
|
|
||||||
|
|
||||||
## librairies
|
## librairies
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,9 @@ Werkzeug==2.2.3
|
|||||||
joblib==1.4.2
|
joblib==1.4.2
|
||||||
pyarrow
|
pyarrow
|
||||||
pandas-ta
|
pandas-ta
|
||||||
ydata-profiling
|
ydata-profiling
|
||||||
|
tensorflow
|
||||||
|
keras
|
||||||
|
scikit-learn
|
||||||
|
pydot
|
||||||
|
graphviz
|
||||||
62
src/app.py
62
src/app.py
@@ -8,6 +8,13 @@ import joblib
|
|||||||
from io import TextIOWrapper
|
from io import TextIOWrapper
|
||||||
from ydata_profiling import ProfileReport
|
from ydata_profiling import ProfileReport
|
||||||
|
|
||||||
|
# model
|
||||||
|
from sklearn.model_selection import train_test_split
|
||||||
|
from sklearn.preprocessing import StandardScaler
|
||||||
|
from tensorflow.keras.models import Sequential
|
||||||
|
from tensorflow.keras.layers import Dense
|
||||||
|
from tensorflow.keras.utils import plot_model
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
FREQTRADE_USERDATA_DIR = '/mnt/external'
|
FREQTRADE_USERDATA_DIR = '/mnt/external'
|
||||||
|
|
||||||
@@ -121,6 +128,43 @@ def read_feather(filename):
|
|||||||
# dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
|
# dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
|
||||||
# dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
|
# dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
|
||||||
|
|
||||||
|
# Choisir les colonnes techniques comme variables d'entrée (X)
|
||||||
|
feature_cols = ['rsi', 'sma20', 'sma5_1h', 'volume']
|
||||||
|
df = dataframe
|
||||||
|
# Variable cible
|
||||||
|
df['target'] = df['futur_price_1h']
|
||||||
|
|
||||||
|
# Supprimer les lignes avec des NaN
|
||||||
|
df.dropna(subset=feature_cols + ['target'], inplace=True)
|
||||||
|
|
||||||
|
X = df[feature_cols].values
|
||||||
|
y = df['target'].values
|
||||||
|
|
||||||
|
# Normalisation
|
||||||
|
scaler = StandardScaler()
|
||||||
|
X = scaler.fit_transform(X)
|
||||||
|
|
||||||
|
# Split
|
||||||
|
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
|
||||||
|
|
||||||
|
# Modèle
|
||||||
|
model = Sequential([
|
||||||
|
Dense(64, input_dim=X.shape[1], activation='relu'),
|
||||||
|
Dense(32, activation='relu'),
|
||||||
|
Dense(1) # Prédiction continue
|
||||||
|
])
|
||||||
|
|
||||||
|
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
|
||||||
|
|
||||||
|
# Entraînement
|
||||||
|
model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_test, y_test))
|
||||||
|
|
||||||
|
loss, mae = model.evaluate(X_test, y_test)
|
||||||
|
print(f"Erreur moyenne absolue : {mae:.4f}")
|
||||||
|
|
||||||
|
model.summary()
|
||||||
|
|
||||||
|
plot_model(model, show_shapes=True, show_layer_names=True, to_file=FREQTRADE_USERDATA_DIR + "/reports/model.png")
|
||||||
return dataframe.to_json(orient="records")
|
return dataframe.to_json(orient="records")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
@@ -185,6 +229,24 @@ def get_chart_data():
|
|||||||
|
|
||||||
return df.to_json(orient="records") #jsonify(chart_data)
|
return df.to_json(orient="records") #jsonify(chart_data)
|
||||||
|
|
||||||
|
@app.route('/model')
|
||||||
|
def show_model():
|
||||||
|
# Créer un exemple de modèle si non encore généré
|
||||||
|
model_path = FREQTRADE_USERDATA_DIR + "/reports/model.png"
|
||||||
|
if not os.path.exists(model_path):
|
||||||
|
model = Sequential([
|
||||||
|
Dense(64, input_shape=(6,), activation='relu'),
|
||||||
|
Dense(32, activation='relu'),
|
||||||
|
Dense(1)
|
||||||
|
])
|
||||||
|
plot_model(model, to_file=model_path, show_shapes=True, show_layer_names=True)
|
||||||
|
return render_template('model.html', model_image=model_path)
|
||||||
|
|
||||||
|
# Route pour servir les fichiers statiques (optionnelle si bien configuré)
|
||||||
|
@app.route('/static/<path:filename>')
|
||||||
|
def static_files(filename):
|
||||||
|
return send_from_directory('static', filename)
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -329,6 +329,30 @@ function renderChart(data, filename, create_columns) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Achat
|
||||||
|
series.push({
|
||||||
|
name: 'Buy',
|
||||||
|
type: 'scatter',
|
||||||
|
symbolSize: 10,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#00aa00'
|
||||||
|
},
|
||||||
|
// label: {
|
||||||
|
// show: true,
|
||||||
|
// position: 'top', // ou 'right', 'inside', etc.
|
||||||
|
// formatter: function (param) {
|
||||||
|
// return param.value[2]; // ou par ex. param.value[1] pour afficher le prix
|
||||||
|
// },
|
||||||
|
// fontSize: 12,
|
||||||
|
// color: '#000'
|
||||||
|
// },
|
||||||
|
data: data
|
||||||
|
.filter(d => d.enter_long === 1)
|
||||||
|
.map(d => {
|
||||||
|
const date = new Date(d.date).toLocaleString('fr-FR', options);
|
||||||
|
return [date, d.close, d.enter_tag];
|
||||||
|
})
|
||||||
|
})
|
||||||
// Volume
|
// Volume
|
||||||
series.push({
|
series.push({
|
||||||
name: 'Volume',
|
name: 'Volume',
|
||||||
@@ -349,6 +373,7 @@ function renderChart(data, filename, create_columns) {
|
|||||||
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)
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
if (element.checked) {
|
if (element.checked) {
|
||||||
|
|
||||||
@@ -489,7 +514,14 @@ function renderChart(data, filename, create_columns) {
|
|||||||
li.classList.add('is-1d');
|
li.classList.add('is-1d');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
document.querySelectorAll('.indicatorsReport li').forEach(li => {
|
||||||
|
if (li.textContent.trim().endsWith('_1h')) {
|
||||||
|
li.classList.add('is-1h');
|
||||||
|
}
|
||||||
|
if (li.textContent.trim().endsWith('_1d')) {
|
||||||
|
li.classList.add('is-1d');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFeather(filename) {
|
function loadFeather(filename) {
|
||||||
|
|||||||
@@ -52,6 +52,8 @@
|
|||||||
|
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
|
<a href="/model">Voir le modèle</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id='content' class="content">
|
<div id='content' class="content">
|
||||||
<div id="json-tabs">
|
<div id="json-tabs">
|
||||||
|
|||||||
11
src/templates/model.html
Normal file
11
src/templates/model.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Modèle de réseau</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Structure du modèle</h2>
|
||||||
|
<img src="/{{ model_image }}" alt="Modèle Keras" style="max-width:100%;">
|
||||||
|
<br><a href="/">Retour</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user