Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a59a7352c8 | |||
| 528422aa24 |
@@ -1,3 +1 @@
|
|||||||
.vscode
|
.vscode
|
||||||
.venv
|
|
||||||
__pycache__/
|
|
||||||
-29
@@ -1,29 +0,0 @@
|
|||||||
# Use an official Python runtime as a parent image
|
|
||||||
FROM python:3.10
|
|
||||||
|
|
||||||
# Set the working directory to C:\app
|
|
||||||
WORKDIR C:\app
|
|
||||||
|
|
||||||
# Install necessary system packages
|
|
||||||
# Note: Windows containers don't use apt-get, so we skip this step on Windows
|
|
||||||
|
|
||||||
# Copy the current directory contents into the container at C:\app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Install TA-Lib
|
|
||||||
# COPY app/Tab-Lib-deps/ta-lib-0.4.0-src.tar.gz .
|
|
||||||
# RUN New-Item -ItemType Directory -Path C:\ta-lib
|
|
||||||
# RUN tar -zxvf .\ta-lib-0.4.0-src.tar.gz -C C:\ta-lib --strip-components=1
|
|
||||||
# RUN Remove-Item .\ta-lib-0.4.0-src.tar.gz -Force
|
|
||||||
|
|
||||||
# Install any needed packages specified in requirements.txt
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Make port 5000 available to the world outside this container
|
|
||||||
EXPOSE 5000
|
|
||||||
|
|
||||||
# Define environment variable
|
|
||||||
ENV NAME trading-bot
|
|
||||||
|
|
||||||
# Run app.py when the container launches
|
|
||||||
CMD ["flask", "run", "--host=0.0.0.0"]
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#import <ZmqMql4Connector.mqh>
|
||||||
|
|
||||||
|
// Define the ZeroMQ server endpoint
|
||||||
|
#define ZMQ_SERVER_ENDPOINT "tcp://*:5900"
|
||||||
|
// Replace 'metatrader-port' with the port number you want to use for communication
|
||||||
|
|
||||||
|
// Define the ZeroMQ socket and context
|
||||||
|
CZmqMql4Server g_server;
|
||||||
|
CZmqContext g_context;
|
||||||
|
|
||||||
|
// Define a function to handle incoming messages
|
||||||
|
void OnMessageReceived(string message)
|
||||||
|
{
|
||||||
|
// Process the received message and perform necessary actions
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Send a response message (if needed)
|
||||||
|
string responseMessage = "Response from MetaTrader";
|
||||||
|
g_server.Send(responseMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The start function that is called when the EA/script is initialized
|
||||||
|
int OnInit()
|
||||||
|
{
|
||||||
|
// Initialize the ZeroMQ server
|
||||||
|
if (!g_server.Initialize(ZMQ_SERVER_ENDPOINT, g_context, OnMessageReceived))
|
||||||
|
{
|
||||||
|
Print("Failed to initialize ZeroMQ server");
|
||||||
|
return INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the ZeroMQ server
|
||||||
|
if (!g_server.Start())
|
||||||
|
{
|
||||||
|
Print("Failed to start ZeroMQ server");
|
||||||
|
return INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return INIT_SUCCEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main function that is called on each tick
|
||||||
|
void OnTick()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// The deinitialization function that is called when the EA/script is stopped
|
||||||
|
void OnDeinit(const int reason)
|
||||||
|
{
|
||||||
|
// Stop the ZeroMQ server
|
||||||
|
g_server.Stop();
|
||||||
|
|
||||||
|
// Deinitialize the ZeroMQ server and context
|
||||||
|
g_server.Deinitialize();
|
||||||
|
g_context.Terminalize();
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// ZmqMql4Connector.mqh
|
||||||
|
|
||||||
|
// Define the ZMQ message callback function type
|
||||||
|
typedef void OnZmqMessageReceived(string message);
|
||||||
|
|
||||||
|
class CZmqMql4Server
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
string m_endpoint; // ZeroMQ server endpoint
|
||||||
|
int m_socket; // ZeroMQ socket
|
||||||
|
int m_context; // ZeroMQ context
|
||||||
|
OnZmqMessageReceived @m_callback; // Message callback function
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
CZmqMql4Server()
|
||||||
|
{
|
||||||
|
m_socket = -1;
|
||||||
|
m_context = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~CZmqMql4Server()
|
||||||
|
{
|
||||||
|
Deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the ZeroMQ server
|
||||||
|
bool Initialize(string endpoint, OnZmqMessageReceived @callback)
|
||||||
|
{
|
||||||
|
m_endpoint = endpoint;
|
||||||
|
m_callback = @callback;
|
||||||
|
|
||||||
|
m_context = zmq_init(1);
|
||||||
|
if (m_context == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_socket = zmq_socket(m_context, ZMQ_REP);
|
||||||
|
if (m_socket == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int bindResult = zmq_bind(m_socket, m_endpoint);
|
||||||
|
if (bindResult == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the ZeroMQ server
|
||||||
|
bool Start()
|
||||||
|
{
|
||||||
|
if (m_socket == -1 || m_context == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
string message = Receive();
|
||||||
|
if (message != "")
|
||||||
|
m_callback(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the ZeroMQ server
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
if (m_socket != -1)
|
||||||
|
zmq_close(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a message from the server
|
||||||
|
void Send(string message)
|
||||||
|
{
|
||||||
|
if (m_socket != -1)
|
||||||
|
zmq_send(m_socket, message, StringLen(message), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive a message in the server
|
||||||
|
string Receive()
|
||||||
|
{
|
||||||
|
if (m_socket != -1)
|
||||||
|
{
|
||||||
|
string message;
|
||||||
|
int receivedBytes = zmq_recv(m_socket, message, 4096, 0);
|
||||||
|
if (receivedBytes > 0)
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deinitialize the ZeroMQ server
|
||||||
|
void Deinitialize()
|
||||||
|
{
|
||||||
|
if (m_socket != -1)
|
||||||
|
zmq_close(m_socket);
|
||||||
|
if (m_context != -1)
|
||||||
|
zmq_term(m_context);
|
||||||
|
|
||||||
|
m_socket = -1;
|
||||||
|
m_context = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
+289
@@ -0,0 +1,289 @@
|
|||||||
|
from keras.optimizers import Adam
|
||||||
|
from keras.layers import Dense, Dropout
|
||||||
|
from keras.models import Sequential
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import talib
|
||||||
|
from sklearn.preprocessing import MinMaxScaler
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import zmq
|
||||||
|
|
||||||
|
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
||||||
|
|
||||||
|
|
||||||
|
def start_mt5_bot():
|
||||||
|
# Define the symbols and timeframes
|
||||||
|
symbol = 'EURUSD'
|
||||||
|
timeframe = 'H1' # H1 timeframe (1 hour)
|
||||||
|
|
||||||
|
# Set up initial variables
|
||||||
|
lot_size = 0.01
|
||||||
|
stop_loss = 100
|
||||||
|
take_profit = 150
|
||||||
|
|
||||||
|
# Define TensorFlow neural network model
|
||||||
|
def create_neural_network_model(input_shape):
|
||||||
|
model = Sequential()
|
||||||
|
model.add(Dense(64, activation='relu', input_shape=input_shape))
|
||||||
|
model.add(Dropout(0.2))
|
||||||
|
model.add(Dense(64, activation='relu'))
|
||||||
|
model.add(Dropout(0.2))
|
||||||
|
model.add(Dense(1, activation='sigmoid'))
|
||||||
|
return model
|
||||||
|
|
||||||
|
# Define input shape for the neural network
|
||||||
|
# Adjust the input shape based on your features and data
|
||||||
|
input_shape = (10,)
|
||||||
|
|
||||||
|
# Create the neural network model
|
||||||
|
neural_network_model = create_neural_network_model(input_shape)
|
||||||
|
|
||||||
|
# Compile the model
|
||||||
|
neural_network_model.compile(optimizer=Adam(
|
||||||
|
learning_rate=0.001), loss='binary_crossentropy')
|
||||||
|
|
||||||
|
def get_historical_data(socket):
|
||||||
|
# Request historical data from MetaTrader app
|
||||||
|
socket.send_string(
|
||||||
|
f"GET_HISTORICAL_DATA {symbol} {timeframe} 01/01/2022 31/12/2022")
|
||||||
|
|
||||||
|
# Receive historical data from MetaTrader app
|
||||||
|
response = socket.recv_string()
|
||||||
|
data = pd.read_json(response)
|
||||||
|
df = data[['open', 'high', 'low', 'close', 'tick_volume']]
|
||||||
|
return df
|
||||||
|
|
||||||
|
def calculate_indicators_and_detect_patterns(df):
|
||||||
|
# Calculate RSI
|
||||||
|
rsi_period = 14
|
||||||
|
df['rsi'] = talib.RSI(df['close'], rsi_period)
|
||||||
|
|
||||||
|
# Calculate MACD
|
||||||
|
macd_fast_period = 12
|
||||||
|
macd_slow_period = 26
|
||||||
|
macd_signal_period = 9
|
||||||
|
_, _, df['macd'] = talib.MACD(df['close'], fastperiod=macd_fast_period,
|
||||||
|
slowperiod=macd_slow_period, signalperiod=macd_signal_period)
|
||||||
|
|
||||||
|
# Detect divergence based on RSI and MACD
|
||||||
|
df['rsi_divergence'] = np.where(
|
||||||
|
df['rsi'].diff().shift(-1) * df['macd'].diff().shift(-1) < 0, True, False)
|
||||||
|
df['macd_divergence'] = np.where(
|
||||||
|
df['macd'].diff().shift(-1) * df['rsi'].diff().shift(-1) < 0, True, False)
|
||||||
|
|
||||||
|
# Detect support and resistance levels
|
||||||
|
window = 10
|
||||||
|
df['support'] = df['low'].rolling(window).min()
|
||||||
|
df['resistance'] = df['high'].rolling(window).max()
|
||||||
|
|
||||||
|
# Determine trend direction
|
||||||
|
df['trend_200'] = df['close'].rolling(window=200).mean()
|
||||||
|
df['trend_50'] = df['close'].rolling(window=50).mean()
|
||||||
|
|
||||||
|
# Detect double tops and bottoms
|
||||||
|
df['pattern'] = 'None'
|
||||||
|
df['top_pattern'] = np.where((df['high'].shift(1) < df['high']) & (df['high'].shift(-1) < df['high']) &
|
||||||
|
(df['high'].shift(2) > df['high']) & (
|
||||||
|
df['high'].shift(-2) > df['high']),
|
||||||
|
'Double Top', 'None')
|
||||||
|
df.loc[df['top_pattern'] != 'None', 'pattern'] = df['top_pattern']
|
||||||
|
df['bottom_pattern'] = np.where((df['low'].shift(1) > df['low']) & (df['low'].shift(-1) > df['low']) &
|
||||||
|
(df['low'].shift(2) < df['low']) & (
|
||||||
|
df['low'].shift(-2) < df['low']),
|
||||||
|
'Double Bottom', 'None')
|
||||||
|
df.loc[df['bottom_pattern'] != 'None',
|
||||||
|
'pattern'] = df['bottom_pattern']
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def generate_signals(df):
|
||||||
|
# Determine trade signals based on divergences, patterns, and trend direction
|
||||||
|
df['signal'] = 'None'
|
||||||
|
df['divergence_signal'] = np.where((df['rsi_divergence'] == True) & (df['pattern'] != 'None'), 'Both',
|
||||||
|
np.where(df['rsi_divergence'] == True, 'RSI', 'Pattern'))
|
||||||
|
df['strongest_divergence_signal'] = df[[
|
||||||
|
'divergence_signal', 'macd_divergence']].max(axis=1)
|
||||||
|
df['support_resistance_signal'] = np.where(df['close'] > df['resistance'], 'Resistance',
|
||||||
|
np.where(df['close'] < df['support'], 'Support', 'None'))
|
||||||
|
df['trend_signal'] = np.where(df['close'] > df['trend_200'], 'Uptrend',
|
||||||
|
np.where(df['close'] < df['trend_200'], 'Downtrend', 'None'))
|
||||||
|
for i in range(1, len(df)):
|
||||||
|
prev_divergence_signal = df['divergence_signal'].iloc[i - 1]
|
||||||
|
curr_divergence_signal = df['divergence_signal'].iloc[i]
|
||||||
|
strongest_divergence_signal = df['strongest_divergence_signal'].iloc[i]
|
||||||
|
support_resistance_signal = df['support_resistance_signal'].iloc[i]
|
||||||
|
trend_signal = df['trend_signal'].iloc[i]
|
||||||
|
|
||||||
|
if strongest_divergence_signal != 'None':
|
||||||
|
df['signal'].iloc[i] = strongest_divergence_signal
|
||||||
|
elif prev_divergence_signal == curr_divergence_signal and curr_divergence_signal != 'None':
|
||||||
|
df['signal'].iloc[i] = curr_divergence_signal
|
||||||
|
else:
|
||||||
|
df['signal'].iloc[i] = support_resistance_signal
|
||||||
|
|
||||||
|
if trend_signal != 'None' and df['signal'].iloc[i] != 'None':
|
||||||
|
df['signal'].iloc[i] = trend_signal
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def execute_trade(signal, df, socket):
|
||||||
|
# Implement risk management and trade execution logic based on the signals generated
|
||||||
|
# Update TensorFlow neural network model with trade outcome
|
||||||
|
|
||||||
|
# Calculate risk and position size based on lot size, stop loss, and take profit
|
||||||
|
risk = lot_size * stop_loss
|
||||||
|
strongest_divergence_signal = df['strongest_divergence_signal'].iloc[-1]
|
||||||
|
if strongest_divergence_signal == 'RSI':
|
||||||
|
risk *= 1.2 # Increase risk by 20% if RSI divergence is the strongest
|
||||||
|
elif strongest_divergence_signal == 'Pattern':
|
||||||
|
risk *= 1.5 # Increase risk by 50% if pattern divergence is the strongest
|
||||||
|
|
||||||
|
position_size = risk / (take_profit - stop_loss)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if signal == 'Buy':
|
||||||
|
# Place a buy trade
|
||||||
|
socket.send_string(
|
||||||
|
f"PLACE_TRADE {symbol} BUY {lot_size} {stop_loss} {take_profit}")
|
||||||
|
response = socket.recv_string()
|
||||||
|
outcome = 'Win' if response == 'TRADE_EXECUTED' else 'Loss'
|
||||||
|
|
||||||
|
elif signal == 'Sell':
|
||||||
|
# Place a sell trade
|
||||||
|
socket.send_string(
|
||||||
|
f"PLACE_TRADE {symbol} SELL {lot_size} {stop_loss} {take_profit}")
|
||||||
|
response = socket.recv_string()
|
||||||
|
outcome = 'Win' if response == 'TRADE_EXECUTED' else 'Loss'
|
||||||
|
|
||||||
|
# Example trade outcome information
|
||||||
|
trade_outcome = {
|
||||||
|
'pattern': df['pattern'].iloc[-1],
|
||||||
|
'divergence_strength': strongest_divergence_signal,
|
||||||
|
'time': df.index[-1],
|
||||||
|
'trend_direction': df['trend_signal'].iloc[-1],
|
||||||
|
'indicator_used': strongest_divergence_signal,
|
||||||
|
'outcome': outcome
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update TensorFlow neural network model with trade outcome
|
||||||
|
update_neural_network_model(trade_outcome)
|
||||||
|
|
||||||
|
# Example print statements for debugging
|
||||||
|
print(
|
||||||
|
f"Executed {signal} trade with position size: {position_size}")
|
||||||
|
print(f"Trade outcome: {trade_outcome}")
|
||||||
|
|
||||||
|
# Additional logic for trade management, monitoring, etc.
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error executing trade: {str(e)}")
|
||||||
|
|
||||||
|
def update_neural_network_model(trade_outcome):
|
||||||
|
# Implement code to update the neural network model based on trade outcome
|
||||||
|
pattern = trade_outcome['pattern']
|
||||||
|
divergence_strength = trade_outcome['divergence_strength']
|
||||||
|
time = trade_outcome['time']
|
||||||
|
trend_direction = trade_outcome['trend_direction']
|
||||||
|
indicator_used = trade_outcome['indicator_used']
|
||||||
|
outcome = trade_outcome['outcome']
|
||||||
|
|
||||||
|
# Example update code: Append trade outcome information to a dataset for future training
|
||||||
|
trade_data = pd.DataFrame({
|
||||||
|
'pattern': [pattern],
|
||||||
|
'divergence_strength': [divergence_strength],
|
||||||
|
'time': [time],
|
||||||
|
'trend_direction': [trend_direction],
|
||||||
|
'indicator_used': [indicator_used],
|
||||||
|
'outcome': [outcome]
|
||||||
|
})
|
||||||
|
# Append the trade data to the dataset for future training
|
||||||
|
dataset = pd.read_csv('trade_dataset.csv') # Load existing dataset
|
||||||
|
updated_dataset = pd.concat([dataset, trade_data], ignore_index=True)
|
||||||
|
# Save updated dataset
|
||||||
|
updated_dataset.to_csv('trade_dataset.csv', index=False)
|
||||||
|
|
||||||
|
# Example retraining code: Retrain the neural network model with the updated dataset
|
||||||
|
# Preprocess data as per your requirements
|
||||||
|
X_train, y_train = preprocess_data(updated_dataset)
|
||||||
|
# Example retraining step
|
||||||
|
neural_network_model.fit(X_train, y_train, epochs=10, batch_size=32)
|
||||||
|
|
||||||
|
# Save the updated model weights
|
||||||
|
neural_network_model.save_weights('weights/model_weights.h5')
|
||||||
|
|
||||||
|
def preprocess_data(dataset):
|
||||||
|
# Define the numerical features (if any)
|
||||||
|
numerical_features = [] # Update with the actual numerical feature column names
|
||||||
|
|
||||||
|
# Define the input features
|
||||||
|
input_features = dataset[[
|
||||||
|
'pattern', 'divergence_strength', 'trend_direction', 'indicator_used']]
|
||||||
|
|
||||||
|
# Convert categorical features to one-hot encoding
|
||||||
|
input_features = pd.get_dummies(input_features)
|
||||||
|
|
||||||
|
# Normalize numerical features (if any)
|
||||||
|
if numerical_features:
|
||||||
|
scaler = MinMaxScaler()
|
||||||
|
input_features[numerical_features] = scaler.fit_transform(
|
||||||
|
input_features[numerical_features])
|
||||||
|
|
||||||
|
# Extract target labels from the dataset
|
||||||
|
target_labels = dataset['outcome']
|
||||||
|
|
||||||
|
# Convert target labels to numerical representation (0s and 1s)
|
||||||
|
target_labels = target_labels.map({'Loss': 0, 'Win': 1})
|
||||||
|
|
||||||
|
# Return the preprocessed input features and target labels
|
||||||
|
return input_features, target_labels
|
||||||
|
|
||||||
|
def visualize_data(df):
|
||||||
|
plt.figure(figsize=(10, 6))
|
||||||
|
plt.plot(df.index, df['close'], label='Close')
|
||||||
|
# Add visualizations for other indicators, levels, and patterns
|
||||||
|
plt.scatter(df[df['pattern'] == 'Double Top'].index, df[df['pattern'] == 'Double Top']['high'],
|
||||||
|
color='red', marker='v', label='Double Top')
|
||||||
|
plt.scatter(df[df['pattern'] == 'Double Bottom'].index, df[df['pattern'] == 'Double Bottom']['low'],
|
||||||
|
color='green', marker='^', label='Double Bottom')
|
||||||
|
plt.legend()
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
# Connect to MetaTrader app using ZeroMQ
|
||||||
|
context = zmq.Context()
|
||||||
|
socket = context.socket(zmq.REQ)
|
||||||
|
socket.connect("tcp://metatrader_service:5900")
|
||||||
|
# Replace 'metatrader-container-ip' and 'metatrader-port' with the IP address and port of the MetaTrader container
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# Get historical data
|
||||||
|
df = get_historical_data(socket)
|
||||||
|
|
||||||
|
# Calculate indicators and detect patterns
|
||||||
|
df = calculate_indicators_and_detect_patterns(df)
|
||||||
|
|
||||||
|
# Generate trade signals
|
||||||
|
df = generate_signals(df)
|
||||||
|
|
||||||
|
# Execute trades
|
||||||
|
for i in range(1, len(df)):
|
||||||
|
signal = df['signal'].iloc[i]
|
||||||
|
if signal != 'None':
|
||||||
|
execute_trade(signal, df, socket)
|
||||||
|
|
||||||
|
# Visualize data
|
||||||
|
visualize_data(df)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error running trading bot: {str(e)}")
|
||||||
|
|
||||||
|
# Wait for the next iteration
|
||||||
|
time.sleep(60) # Adjust the time interval as needed
|
||||||
|
|
||||||
|
# Disconnect from ZeroMQ socket
|
||||||
|
socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
# Start the MetaTrader bot
|
||||||
|
start_mt5_bot()
|
||||||
Regular → Executable
+3
-5
@@ -1,9 +1,7 @@
|
|||||||
# requirements.txt
|
|
||||||
pandas
|
|
||||||
numpy
|
numpy
|
||||||
scikit-learn
|
pandas
|
||||||
TA-Lib
|
TA-Lib
|
||||||
matplotlib
|
matplotlib
|
||||||
MetaTrader5
|
scikit-learn
|
||||||
tensorflow
|
tensorflow
|
||||||
flask
|
pyzmq
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import socketio
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Connect to the trading bot container
|
||||||
|
sio = socketio.Client()
|
||||||
|
# Replace with the appropriate URL and port of your trading bot container
|
||||||
|
sio.connect('tcp://trading_bot:3000')
|
||||||
|
|
||||||
|
# Handle events from the trading bot container
|
||||||
|
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
def connect():
|
||||||
|
print('Connected to trading bot container')
|
||||||
|
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
def disconnect():
|
||||||
|
print('Disconnected from trading bot container')
|
||||||
|
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
def send_trade_signal(signal):
|
||||||
|
print(f'Received trade signal: {signal}')
|
||||||
|
# Process the trade signal and execute trades through MetaTrader 5
|
||||||
|
|
||||||
|
|
||||||
|
# Main loop to keep the script running
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
+50
-13
@@ -1,17 +1,54 @@
|
|||||||
version: '3'
|
version: "3"
|
||||||
services:
|
services:
|
||||||
trading-bot:
|
metatrader_service:
|
||||||
|
image: ejtrader/metatrader:5
|
||||||
|
container_name: metatrader
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- DISPLAY=$DISPLAY
|
||||||
|
privileged: true
|
||||||
|
volumes:
|
||||||
|
- ejtraderMT:/data
|
||||||
|
ports:
|
||||||
|
- "5900:5900"
|
||||||
|
- "15555:15555"
|
||||||
|
- "15556:15556"
|
||||||
|
- "15557:15557"
|
||||||
|
- "15558:15558"
|
||||||
|
networks:
|
||||||
|
- trading_network
|
||||||
|
|
||||||
|
trading_bot:
|
||||||
|
container_name: trading_bot
|
||||||
|
restart: unless-stopped
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: docker/DockerFile
|
||||||
ports:
|
|
||||||
- "5000:5000"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./src:/app/src
|
- ./app:/app
|
||||||
- ./static:/app/static
|
ports:
|
||||||
- ./templates:/app/templates
|
- 3000:3000
|
||||||
- ./model_weights.h5:/app/model_weights.h5
|
depends_on:
|
||||||
environment:
|
- metatrader_service
|
||||||
- FLASK_APP=main.py
|
networks:
|
||||||
- FLASK_RUN_HOST=0.0.0.0
|
- trading_network
|
||||||
- PYTHONUNBUFFERED=1
|
|
||||||
|
mt5_bridge:
|
||||||
|
container_name: mt5_bridge
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/DockerFile.mt5_bridge
|
||||||
|
volumes:
|
||||||
|
- ./bridge:/bridge
|
||||||
|
depends_on:
|
||||||
|
- metatrader_service
|
||||||
|
- trading_bot
|
||||||
|
networks:
|
||||||
|
- trading_network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
trading_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
ejtraderMT: {}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Use an official Python runtime as the base image
|
||||||
|
FROM python:3.10
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the requirements file to the working directory
|
||||||
|
COPY app/requirements.txt .
|
||||||
|
|
||||||
|
# Copy the Tab-Lib dependencies to the working directory
|
||||||
|
COPY app/Tab-Lib-deps/ta-lib-0.4.0-src.tar.gz .
|
||||||
|
|
||||||
|
# Extract and install Tab-Lib
|
||||||
|
RUN tar -xzf ta-lib-0.4.0-src.tar.gz && \
|
||||||
|
rm ta-lib-0.4.0-src.tar.gz && \
|
||||||
|
cd ta-lib && \
|
||||||
|
./configure --prefix=/usr && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Install the Python dependencies
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
RUN pip install ejtraderMT -U
|
||||||
|
|
||||||
|
# Copy the application code to the container
|
||||||
|
COPY app/ .
|
||||||
|
|
||||||
|
# Run the bot script using xvfb-run
|
||||||
|
CMD [ "python", "bot.py" ]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM python:3.10
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the bridge script to the container
|
||||||
|
COPY bridge/mt5_bridge.py .
|
||||||
|
|
||||||
|
# Install any dependencies required by the bridge script
|
||||||
|
RUN pip install python-socketio python-engineio requests
|
||||||
|
|
||||||
|
CMD ["python", "mt5_bridge.py"]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
FROM ejtrader/metatrader:5
|
||||||
|
|
||||||
|
# Add your custom configuration and scripts here, if needed
|
||||||
|
|
||||||
|
# Start MetaTrader 5
|
||||||
|
CMD ["/root/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe"]
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
"""
|
|
||||||
Main script for running the trading bot with a web interface.
|
|
||||||
|
|
||||||
This script initializes the MetaTrader 5 connection, runs the trading bot, and integrates with a web interface for user credentials.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import time
|
|
||||||
from flask import Flask, render_template, request, redirect, json, Response
|
|
||||||
from src.connectors import mt5_connector
|
|
||||||
from src.models import neural_network_model
|
|
||||||
from src.strategies.trading_strategy import get_historical_data, calculate_indicators_and_detect_patterns, generate_trade_signals, execute_trade
|
|
||||||
from src.utils.visualization import plot_trade_signals
|
|
||||||
import threading
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
# Define input shape for the neural network
|
|
||||||
input_shape = (11,) # Adjust the input shape based on your features and data
|
|
||||||
|
|
||||||
# Create the neural network model
|
|
||||||
neural_network_model = neural_network_model.create_neural_network_model(input_shape)
|
|
||||||
|
|
||||||
# Global state to track whether MT5 is initialized
|
|
||||||
mt5_initialized = False
|
|
||||||
latest_trade_signals = []
|
|
||||||
|
|
||||||
|
|
||||||
# Web Interface Routes
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
|
||||||
"""Render the main page with the login form."""
|
|
||||||
return render_template('index.html')
|
|
||||||
|
|
||||||
@app.route('/login', methods=['POST'])
|
|
||||||
def login():
|
|
||||||
"""
|
|
||||||
Handle the login form submission.
|
|
||||||
|
|
||||||
If the credentials are valid, start the trading bot with the provided credentials.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- str: HTML response.
|
|
||||||
"""
|
|
||||||
global mt5_initialized
|
|
||||||
if request.method == 'POST':
|
|
||||||
credentials = {
|
|
||||||
'username': request.form['username'],
|
|
||||||
'password': request.form['password'],
|
|
||||||
'server': request.form['server'],
|
|
||||||
'path': request.form['path']
|
|
||||||
}
|
|
||||||
if mt5_connector.connect_to_mt5(credentials):
|
|
||||||
# Set MT5 initialization state to True
|
|
||||||
mt5_initialized = True
|
|
||||||
# Redirect to the main dashboard or another page
|
|
||||||
return redirect('/dashboard')
|
|
||||||
else:
|
|
||||||
return render_template('index.html', error='Invalid credentials. Please try again.')
|
|
||||||
|
|
||||||
@app.route('/dashboard')
|
|
||||||
def dashboard():
|
|
||||||
# Replace these with the actual MetaTrader data retrieval logic
|
|
||||||
mt5_data = mt5_connector.get_account_info() # Replace with the actual method to get account info
|
|
||||||
user_data = {'username': mt5_data.name, 'account_balance': mt5_data.balance, 'currency': mt5_data.currency}
|
|
||||||
username = user_data.get('username', 'N/A')
|
|
||||||
account_balance = user_data.get('account_balance', 'N/A')
|
|
||||||
account_currency = user_data.get('currency', 'N/A')
|
|
||||||
|
|
||||||
return render_template('dashboard.html', username=username, account_balance=account_balance, account_currency=account_currency)
|
|
||||||
|
|
||||||
# Flask app routes
|
|
||||||
|
|
||||||
@app.route('/start_ml_bot', methods=['POST'])
|
|
||||||
def start_ml_bot():
|
|
||||||
"""
|
|
||||||
Handle the request to start the ML bot.
|
|
||||||
"""
|
|
||||||
# Start the ML bot
|
|
||||||
threading.Thread(target=run_trading_bot_web_interface).start()
|
|
||||||
|
|
||||||
# Return an empty response
|
|
||||||
return Response(status=200)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/stop_ml_bot", methods=['GET'])
|
|
||||||
def stop_ml_bot():
|
|
||||||
mt5_connector.stop_mt5_ml_bot()
|
|
||||||
redirect('/dashboard')
|
|
||||||
|
|
||||||
def map_signal_priority(signal_priority):
|
|
||||||
# Define a mapping for string values to integers
|
|
||||||
signal_mapping = {
|
|
||||||
'Both': 1,
|
|
||||||
'Pattern': 2,
|
|
||||||
'RSI': 3
|
|
||||||
# Add more mappings as needed
|
|
||||||
}
|
|
||||||
|
|
||||||
# Use the mapping, default to 0 if not found
|
|
||||||
return signal_mapping.get(signal_priority, 0)
|
|
||||||
# Main Trading Bot Logic
|
|
||||||
|
|
||||||
def run_trading_bot_web_interface():
|
|
||||||
"""
|
|
||||||
Run the trading bot using MetaTrader 5 credentials from the web interface.
|
|
||||||
"""
|
|
||||||
global latest_trade_signals
|
|
||||||
historical_data_df = pd.DataFrame()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
symbol = 'EURUSD'
|
|
||||||
lot_size = 0.01
|
|
||||||
stop_loss = 100
|
|
||||||
take_profit = 200
|
|
||||||
|
|
||||||
# Get the latest historical data
|
|
||||||
historical_data_df = get_historical_data(symbol, historical_data_df)
|
|
||||||
|
|
||||||
# Calculate indicators and detect patterns for the latest data
|
|
||||||
df = calculate_indicators_and_detect_patterns(historical_data_df)
|
|
||||||
|
|
||||||
# Generate trade signals for the latest data
|
|
||||||
df = generate_trade_signals(df)
|
|
||||||
df.to_csv('your_file.csv', sep='\t', index=False)
|
|
||||||
|
|
||||||
# Inside the run_trading_bot_web_interface function
|
|
||||||
latest_trade_signals = df.replace({pd.NA: 'null'}).to_json(orient='records')
|
|
||||||
|
|
||||||
|
|
||||||
# Execute trades
|
|
||||||
for i in range(len(df)):
|
|
||||||
|
|
||||||
signal_priority = df['signal'].iloc[i] # Replace with your actual value
|
|
||||||
mapped_priority = map_signal_priority(signal_priority)
|
|
||||||
|
|
||||||
if mapped_priority != 0:
|
|
||||||
execute_trade(mapped_priority, df, symbol, lot_size, stop_loss, take_profit)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error running trading bot: {str(e)}")
|
|
||||||
|
|
||||||
# Wait for the next iteration
|
|
||||||
time.sleep(60) # Adjust the time interval as needed
|
|
||||||
|
|
||||||
@app.route('/get_latest_trade_signals', methods=['GET'])
|
|
||||||
def get_latest_trade_signals():
|
|
||||||
global latest_trade_signals
|
|
||||||
return json.dumps(latest_trade_signals)
|
|
||||||
|
|
||||||
# Start the Flask app
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(debug=True)
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Start the X server
|
||||||
|
Xvfb :0 -screen 0 1024x768x16 &
|
||||||
|
|
||||||
|
# Set the X display
|
||||||
|
export DISPLAY=:0
|
||||||
|
|
||||||
|
# Install necessary dependencies using winetricks
|
||||||
|
winetricks -q corefonts
|
||||||
|
|
||||||
|
# Add a small delay for X server initialization
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Run MetaTrader 5
|
||||||
|
exec su - trader -c 'wine "/home/trader/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe"'
|
||||||
|
|
||||||
|
# Clean up X server resources
|
||||||
|
killall Xvfb
|
||||||
|
rm -rf /tmp/.X11-unix
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# mt5_connector.py
|
|
||||||
|
|
||||||
"""
|
|
||||||
Module for connecting to MetaTrader 5 (MT5) using the MetaTrader5 Python package.
|
|
||||||
|
|
||||||
This module provides functions for initializing and connecting to MT5, along with error handling.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import MetaTrader5 as mt5
|
|
||||||
|
|
||||||
|
|
||||||
def start_mt5(username: str, password: str, server: str, path: str) -> bool:
|
|
||||||
"""
|
|
||||||
Initialize and start a connection to MetaTrader 5.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- username (str): The MT5 account username.
|
|
||||||
- password (str): The MT5 account password.
|
|
||||||
- server (str): The MT5 trading server.
|
|
||||||
- path (str): The file path to the MetaTrader 5 executable.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- bool: True if successfully initialized, False otherwise.
|
|
||||||
"""
|
|
||||||
# Ensure that all variables are the correct type
|
|
||||||
uname = int(username) # Username must be an int
|
|
||||||
pword = str(password) # Password must be a string
|
|
||||||
trading_server = str(server) # Server must be a string
|
|
||||||
filepath = str(path) # Filepath must be a string
|
|
||||||
|
|
||||||
# Connect to MetaTrader 5
|
|
||||||
if mt5.initialize(login=uname, password=pword, server=trading_server, path=filepath):
|
|
||||||
# Login to MT5
|
|
||||||
if mt5.login(login=uname, password=pword, server=trading_server):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print("Login Fail")
|
|
||||||
quit()
|
|
||||||
return PermissionError
|
|
||||||
else:
|
|
||||||
print("MT5 Initialization Failed")
|
|
||||||
quit()
|
|
||||||
return ConnectionAbortedError
|
|
||||||
|
|
||||||
def connect_to_mt5(credentials: dict):
|
|
||||||
"""
|
|
||||||
Connect to MetaTrader 5.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- credentials (dict): Dictionary containing 'username', 'password', 'server', and 'path'.
|
|
||||||
"""
|
|
||||||
# Start the MetaTrader 5 instance
|
|
||||||
if start_mt5(credentials['username'], credentials['password'], credentials['server'], credentials['path']):
|
|
||||||
print("Connected to MetaTrader 5")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print("Failed to connect to MetaTrader 5")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_account_info():
|
|
||||||
"""
|
|
||||||
Get account information from MetaTrader 5.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- dict: Dictionary containing account information (e.g., username, account balance).
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Fetch account information
|
|
||||||
account_info = mt5.account_info()
|
|
||||||
|
|
||||||
return account_info
|
|
||||||
|
|
||||||
def stop_mt5_ml_bot():
|
|
||||||
|
|
||||||
mt5.shutdown()
|
|
||||||
return "Disconnected from MetaTrader 5"
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
# neural_network_model.py
|
|
||||||
"""
|
|
||||||
Module for defining and managing the TensorFlow Neural Network model.
|
|
||||||
|
|
||||||
This module provides functions to create, compile, and update a simple feedforward neural network
|
|
||||||
model for use in a trading bot.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from keras.models import Sequential, load_model
|
|
||||||
from keras.layers import Dense, Dropout
|
|
||||||
from keras.optimizers import Adam
|
|
||||||
from keras.losses import BinaryCrossentropy
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
def create_neural_network_model(input_shape: tuple) -> Sequential:
|
|
||||||
"""
|
|
||||||
Create a simple feedforward neural network model.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- input_shape (tuple): The shape of the input data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- Sequential: The Keras Sequential model representing the neural network.
|
|
||||||
"""
|
|
||||||
model = Sequential()
|
|
||||||
model.add(Dense(64, activation='relu', input_shape=input_shape))
|
|
||||||
model.add(Dropout(0.2))
|
|
||||||
model.add(Dense(64, activation='relu'))
|
|
||||||
model.add(Dropout(0.2))
|
|
||||||
model.add(Dense(1, activation='sigmoid'))
|
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
def compile_neural_network_model(model: Sequential, learning_rate: float = 0.001) -> None:
|
|
||||||
"""
|
|
||||||
Compile the neural network model.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- model (Sequential): The Keras Sequential model representing the neural network.
|
|
||||||
- learning_rate (float): The learning rate for the Adam optimizer.
|
|
||||||
"""
|
|
||||||
model.compile(optimizer=Adam(learning_rate=learning_rate), loss='binary_crossentropy', metrics=['accuracy'])
|
|
||||||
|
|
||||||
|
|
||||||
def preprocess_data(dataset: pd.DataFrame) -> tuple:
|
|
||||||
"""
|
|
||||||
Preprocess the dataset for training the neural network model.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- dataset (pd.DataFrame): The dataset containing trade outcome information.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- tuple: A tuple containing preprocessed input features and target labels.
|
|
||||||
"""
|
|
||||||
# Define the numerical features (if any)
|
|
||||||
numerical_features = [] # Update with the actual numerical feature column names
|
|
||||||
|
|
||||||
# Define the input features
|
|
||||||
input_features = dataset[[
|
|
||||||
'pattern', 'divergence_strength', 'trend_direction', 'indicator_used']]
|
|
||||||
|
|
||||||
# Convert categorical features to one-hot encoding
|
|
||||||
input_features = pd.get_dummies(input_features)
|
|
||||||
|
|
||||||
# Normalize numerical features (if any)
|
|
||||||
if numerical_features:
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
input_features[numerical_features] = scaler.fit_transform(
|
|
||||||
input_features[numerical_features])
|
|
||||||
|
|
||||||
# Extract target labels from the dataset
|
|
||||||
target_labels = dataset['outcome']
|
|
||||||
|
|
||||||
# Convert target labels to numerical representation (0s and 1s)
|
|
||||||
target_labels = target_labels.map({'Loss': 0, 'Win': 1})
|
|
||||||
|
|
||||||
# Return the preprocessed input features and target labels
|
|
||||||
return input_features, target_labels
|
|
||||||
|
|
||||||
|
|
||||||
def update_neural_network_model(trade_outcome: dict, dataset_path: str) -> None:
|
|
||||||
"""
|
|
||||||
Update the neural network model based on trade outcome.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- trade_outcome (dict): Trade outcome information.
|
|
||||||
- dataset_path (str): The path to the dataset file for updating and saving.
|
|
||||||
"""
|
|
||||||
# Load existing model or create a new one if it doesn't exist
|
|
||||||
try:
|
|
||||||
model = load_model('model_weights.h5')
|
|
||||||
except (OSError, ValueError):
|
|
||||||
# If loading fails, create a new model
|
|
||||||
input_shape = (5,) # Replace with the actual input shape
|
|
||||||
model = create_neural_network_model(input_shape)
|
|
||||||
compile_neural_network_model(model, learning_rate=0.001)
|
|
||||||
|
|
||||||
pattern = trade_outcome['pattern']
|
|
||||||
divergence_strength = trade_outcome['divergence_strength']
|
|
||||||
time = trade_outcome['time']
|
|
||||||
trend_direction = trade_outcome['trend_direction']
|
|
||||||
indicator_used = trade_outcome['indicator_used']
|
|
||||||
outcome = trade_outcome['outcome']
|
|
||||||
|
|
||||||
# Example update code: Append trade outcome information to a dataset for future training
|
|
||||||
trade_data = pd.DataFrame({
|
|
||||||
'pattern': [pattern],
|
|
||||||
'divergence_strength': [divergence_strength],
|
|
||||||
'time': [time],
|
|
||||||
'trend_direction': [trend_direction],
|
|
||||||
'indicator_used': [indicator_used],
|
|
||||||
'outcome': [outcome]
|
|
||||||
})
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Load existing dataset if it exists
|
|
||||||
dataset = pd.read_csv(dataset_path)
|
|
||||||
except (FileNotFoundError, pd.errors.EmptyDataError):
|
|
||||||
# Create an empty dataset if the file doesn't exist or is empty
|
|
||||||
dataset = pd.DataFrame()
|
|
||||||
|
|
||||||
# Concatenate the trade data to the dataset for future training
|
|
||||||
updated_dataset = pd.concat([dataset, trade_data], ignore_index=True)
|
|
||||||
|
|
||||||
# Save updated dataset
|
|
||||||
updated_dataset.to_csv(dataset_path, index=False)
|
|
||||||
|
|
||||||
# Example retraining code: Retrain the neural network model with the updated dataset
|
|
||||||
# Preprocess data as per your requirements
|
|
||||||
X_train, y_train = preprocess_data(updated_dataset) # Implement the preprocess_data function
|
|
||||||
|
|
||||||
# Convert labels to NumPy array and ensure the correct data type
|
|
||||||
y_train = np.array(y_train).astype(float) # Convert to float
|
|
||||||
|
|
||||||
# Ensure labels have the correct shape
|
|
||||||
y_train = y_train.reshape(-1)
|
|
||||||
|
|
||||||
# Example retraining step
|
|
||||||
model.fit(X_train, y_train, epochs=10, batch_size=32)
|
|
||||||
|
|
||||||
# Save the updated model weights
|
|
||||||
model.save_weights('model_weights.h5')
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
# trading_strategy.py
|
|
||||||
"""
|
|
||||||
Module for defining the trading strategy used by the trading bot.
|
|
||||||
|
|
||||||
This module provides functions for generating trade signals based on various indicators,
|
|
||||||
divergences, patterns, and trend directions.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import MetaTrader5 as mt5
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
from talib import abstract
|
|
||||||
from src.models import neural_network_model
|
|
||||||
|
|
||||||
def get_historical_data(symbol: str, existing_data: pd.DataFrame = None) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Retrieve historical data for a given symbol and timeframe from MetaTrader 5.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- symbol (str): The financial instrument symbol (e.g., 'EURUSD').
|
|
||||||
- existing_data (pd.DataFrame): Existing historical data DataFrame.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: DataFrame containing historical data with columns: ['time', 'open', 'high', 'low', 'close', 'tick_volume', 'spread', 'real_volume'].
|
|
||||||
"""
|
|
||||||
print(len(existing_data))
|
|
||||||
if len(existing_data) == 0:
|
|
||||||
# If no existing data, fetch the last 2500 bars
|
|
||||||
rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M1, 0, 2500)
|
|
||||||
df = pd.DataFrame(rates)
|
|
||||||
else:
|
|
||||||
# If existing data is provided, fetch only the latest bar
|
|
||||||
rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M1, 0, 1)
|
|
||||||
new_data = pd.DataFrame(rates)
|
|
||||||
|
|
||||||
# Concatenate the new data to the existing data
|
|
||||||
df = pd.concat([existing_data, new_data])
|
|
||||||
|
|
||||||
# Convert data to DataFrame
|
|
||||||
df['time'] = pd.to_datetime(df['time'], unit='s')
|
|
||||||
df.set_index('time', inplace=True)
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def calculate_patterns(df: pd.DataFrame) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Calculate common trade patterns such as double tops & bottoms, pennants, wedges, and bull and bear flags.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing price and indicator information.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The DataFrame with added columns for detected patterns.
|
|
||||||
"""
|
|
||||||
# Detect Double Tops & Bottoms
|
|
||||||
df['double_top'] = np.where((df['high'].shift(1) > df['high']) & (df['high'].shift(1) > df['high'].shift(2)), 'Double Top', 'None')
|
|
||||||
df['double_bottom'] = np.where((df['low'].shift(1) < df['low']) & (df['low'].shift(1) < df['low'].shift(2)), 'Double Bottom', 'None')
|
|
||||||
|
|
||||||
# Detect Bull and Bear Flags
|
|
||||||
df['bull_flag'] = np.where((df['close'] > abstract.BBANDS(df['close'], timeperiod=5, nbdevup=2.0, nbdevdn=2.0)[0]) & (df['close'].shift(1) < abstract.BBANDS(df['close'].shift(1), timeperiod=5, nbdevup=2.0, nbdevdn=2.0)[0]), 'Bull Flag', 'None')
|
|
||||||
df['bear_flag'] = np.where((df['close'] < abstract.BBANDS(df['close'], timeperiod=5, nbdevup=2.0, nbdevdn=2.0)[2]) & (df['close'].shift(1) > abstract.BBANDS(df['close'].shift(1), timeperiod=5, nbdevup=2.0, nbdevdn=2.0)[2]), 'Bear Flag', 'None')
|
|
||||||
|
|
||||||
# Assign patterns based on conditions
|
|
||||||
df['pattern'] = 'None'
|
|
||||||
conditions = [
|
|
||||||
(df['double_top'] != 'None'),
|
|
||||||
(df['double_bottom'] != 'None'),
|
|
||||||
(df['bull_flag'] != 'None'),
|
|
||||||
(df['bear_flag'] != 'None')
|
|
||||||
]
|
|
||||||
|
|
||||||
choices = ['Double Top', 'Double Bottom', 'Bull Flag', 'Bear Flag']
|
|
||||||
df['pattern'] = np.select(conditions, choices, default='None')
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def calculate_indicators_and_detect_patterns(df: pd.DataFrame) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Generate trade signals based on divergences, patterns, and trend direction.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing indicators, patterns, and trend information.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The DataFrame with added columns for trade signals.
|
|
||||||
"""
|
|
||||||
# Calculate indicators and detect patterns
|
|
||||||
# Add your indicator calculation and pattern detection logic here
|
|
||||||
|
|
||||||
# Example: Calculate RSI
|
|
||||||
df['rsi'] = abstract.RSI(df['close'], timeperiod=14)
|
|
||||||
# print(df['close'].values)
|
|
||||||
|
|
||||||
# Example: Detect RSI divergence
|
|
||||||
df['rsi_divergence'] = (df['rsi'] > 70) & (df['close'] < df['close'].shift())
|
|
||||||
|
|
||||||
# Example: Detect TREND signal
|
|
||||||
df['trend_signal'] = 'None'
|
|
||||||
df['short_ma'] = df['close'].rolling(window=50).mean()
|
|
||||||
df['long_ma'] = df['close'].rolling(window=200).mean()
|
|
||||||
|
|
||||||
df.loc[df['short_ma'] > df['long_ma'], 'trend_signal'] = 'Uptrend'
|
|
||||||
df.loc[df['short_ma'] < df['long_ma'], 'trend_signal'] = 'Downtrend'
|
|
||||||
# Add your MACD divergence detection logic here
|
|
||||||
|
|
||||||
# Example: Detect patterns
|
|
||||||
df['pattern'] = 'None'
|
|
||||||
# Add your pattern detection logic here
|
|
||||||
df = calculate_patterns(df)
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def generate_trade_signals(df: pd.DataFrame) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Generate trade signals based on divergences, patterns, and trend direction.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing indicators, patterns, and trend information.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The DataFrame with added columns for trade signals.
|
|
||||||
"""
|
|
||||||
# Determine trade signals based on divergences, patterns, and trend direction
|
|
||||||
df['signal'] = 'None'
|
|
||||||
df['divergence_signal'] = np.where((df['rsi_divergence'] == True) & (df['pattern'] != 'None'), 'Both',
|
|
||||||
np.where(df['rsi_divergence'] == True, 'RSI', 'Pattern'))
|
|
||||||
df['strongest_divergence_signal'] = df[['divergence_signal']].max(axis=1)
|
|
||||||
|
|
||||||
# Additional conditions for trade signals
|
|
||||||
conditions = [
|
|
||||||
(df['strongest_divergence_signal'] != 'None'),
|
|
||||||
# Placeholder for 'resistance' calculation - replace this with your actual logic
|
|
||||||
(df['close'] > df['close'].rolling(window=10).max()),
|
|
||||||
(df['close'] < df['close'].rolling(window=10).min()),
|
|
||||||
# Use the calculated 'trend_signal' column for trend condition
|
|
||||||
(df['trend_signal'] == 'Uptrend'),
|
|
||||||
(df['trend_signal'] == 'Downtrend'),
|
|
||||||
# Additional condition to check if the pattern is valid
|
|
||||||
(df['pattern'] != 'None'),
|
|
||||||
]
|
|
||||||
|
|
||||||
choices = ['Divergence', 'Resistance', 'Support', 'Uptrend', 'Downtrend', 'Pattern']
|
|
||||||
|
|
||||||
# Ensure that the lengths of conditions and choices are the same
|
|
||||||
if len(conditions) == len(choices):
|
|
||||||
df['support_resistance_signal'] = np.select(conditions, choices, default='None')
|
|
||||||
else:
|
|
||||||
# Handle the case where lengths do not match (print an error message for debugging)
|
|
||||||
print("Error: Lengths of conditions and choices do not match.")
|
|
||||||
df['support_resistance_signal'] = 'None'
|
|
||||||
|
|
||||||
# Iterate over the data points
|
|
||||||
for i in range(1, len(df)):
|
|
||||||
strongest_divergence_signal = df['strongest_divergence_signal'].iloc[i]
|
|
||||||
support_resistance_signal = df['support_resistance_signal'].iloc[i]
|
|
||||||
trend_signal = df['trend_signal'].iloc[i]
|
|
||||||
|
|
||||||
if strongest_divergence_signal != 'None':
|
|
||||||
df.loc[df.index[i], 'signal'] = strongest_divergence_signal
|
|
||||||
elif support_resistance_signal != 'None':
|
|
||||||
df.loc[df.index[i], 'signal'] = support_resistance_signal
|
|
||||||
elif trend_signal != 'None':
|
|
||||||
df.loc[df.index[i], 'signal'] = trend_signal
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def execute_trade(signal_priority, df, symbol, lot_size, stop_loss, take_profit):
|
|
||||||
"""
|
|
||||||
Execute a trade based on the provided signal and trading parameters.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- signal_priority (int): The priority assigned to the trade signal.
|
|
||||||
- df (pd.DataFrame): The DataFrame containing trade-related information.
|
|
||||||
- symbol (str): The financial instrument symbol (e.g., 'EURUSD').
|
|
||||||
- lot_size (float): The size of the trading position.
|
|
||||||
- stop_loss (float): The stop-loss level.
|
|
||||||
- take_profit (float): The take-profit level.
|
|
||||||
"""
|
|
||||||
for index, row in df.iterrows():
|
|
||||||
|
|
||||||
# Additional conditions for Buy trade
|
|
||||||
if (
|
|
||||||
(signal_priority == 3 and row['rsi_divergence'] and row['rsi_value'] < 30 and row['trend_signal'] == 'Downtrend') or
|
|
||||||
(signal_priority == 2 and row['pattern'] == 'Double Bottom' and row['trend_signal'] == 'Downtrend') or
|
|
||||||
(signal_priority == 1 and 40 <= row['rsi_value'] <= 60 and row['pattern'] == 'Bull Flag' and row['trend_signal'] == 'Uptrend') or
|
|
||||||
(signal_priority == 0 and row['rsi_value'] < 30 and row['rsi_divergence'] and row['pattern'] == 'Bull')
|
|
||||||
):
|
|
||||||
# Place a buy trade
|
|
||||||
request = {
|
|
||||||
'action': mt5.TRADE_ACTION_DEAL,
|
|
||||||
'symbol': symbol,
|
|
||||||
'volume': lot_size,
|
|
||||||
'type': mt5.ORDER_TYPE_BUY,
|
|
||||||
'price': mt5.symbol_info_tick(symbol).ask,
|
|
||||||
'sl': mt5.symbol_info_tick(symbol).ask - stop_loss * mt5.symbol_info(symbol).point,
|
|
||||||
'tp': mt5.symbol_info_tick(symbol).ask + take_profit * mt5.symbol_info(symbol).point,
|
|
||||||
'deviation': 0,
|
|
||||||
'magic': 123456,
|
|
||||||
'comment': "Buy trade",
|
|
||||||
'type_time': mt5.ORDER_TIME_GTC,
|
|
||||||
'type_filling': mt5.ORDER_FILLING_IOC,
|
|
||||||
}
|
|
||||||
elif (
|
|
||||||
(signal_priority == 3 and row['rsi_divergence'] and row['rsi_value'] > 70 and row['trend_signal'] == 'Uptrend') or
|
|
||||||
(signal_priority == 2 and row['pattern'] == 'Double Top' and row['trend_signal'] == 'Uptrend') or
|
|
||||||
(signal_priority == 1 and 40 <= row['rsi_value'] <= 60 and row['pattern'] == 'Bear Flag' and row['trend_signal'] == 'Downtrend') or
|
|
||||||
(signal_priority == 0 and row['rsi_value'] > 70 and row['rsi_divergence'] and row['pattern'] == 'Bear')
|
|
||||||
):
|
|
||||||
# Place a sell trade
|
|
||||||
request = {
|
|
||||||
'action': mt5.TRADE_ACTION_DEAL,
|
|
||||||
'symbol': symbol,
|
|
||||||
'volume': lot_size,
|
|
||||||
'type': mt5.ORDER_TYPE_SELL,
|
|
||||||
'price': mt5.symbol_info_tick(symbol).bid,
|
|
||||||
'sl': mt5.symbol_info_tick(symbol).bid + stop_loss * mt5.symbol_info(symbol).point,
|
|
||||||
'tp': mt5.symbol_info_tick(symbol).bid - take_profit * mt5.symbol_info(symbol).point,
|
|
||||||
'deviation': 0,
|
|
||||||
'magic': 123456,
|
|
||||||
'comment': "Sell trade",
|
|
||||||
'type_time': mt5.ORDER_TIME_GTC,
|
|
||||||
'type_filling': mt5.ORDER_FILLING_IOC,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
if signal_priority != 0:
|
|
||||||
|
|
||||||
result = mt5.order_send(request)
|
|
||||||
print(result)
|
|
||||||
outcome = 'Win' if result.retcode == mt5.TRADE_RETCODE_DONE else 'Loss'
|
|
||||||
|
|
||||||
# Example trade outcome information
|
|
||||||
trade_outcome = {
|
|
||||||
'pattern': row['pattern'],
|
|
||||||
'divergence_strength': row['strongest_divergence_signal'],
|
|
||||||
'time': pd.Timestamp.now(),
|
|
||||||
'trend_direction': row['trend_signal'],
|
|
||||||
'indicator_used': row['strongest_divergence_signal'],
|
|
||||||
'outcome': outcome
|
|
||||||
}
|
|
||||||
# Update TensorFlow neural network model with trade outcome
|
|
||||||
neural_network_model.update_neural_network_model(trade_outcome, 'tradedata.csv')
|
|
||||||
|
|
||||||
# Example print statements for debugging
|
|
||||||
print(
|
|
||||||
f"Executed trade with signal priority: {signal_priority}, position size: {lot_size}")
|
|
||||||
print(f"Trade outcome: {trade_outcome}")
|
|
||||||
|
|
||||||
# Additional logic for trade management, monitoring, etc.
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error executing trade: {str(e)}")
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# data_processing.py
|
|
||||||
"""
|
|
||||||
Module for processing and preprocessing data for the trading bot.
|
|
||||||
|
|
||||||
This module provides functions for loading, cleaning, and preprocessing historical price data.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from sklearn.preprocessing import MinMaxScaler
|
|
||||||
|
|
||||||
def load_data(file_path: str) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Load historical price data from a CSV file.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- file_path (str): The path to the CSV file containing historical price data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The DataFrame containing historical price data.
|
|
||||||
"""
|
|
||||||
# Load data from CSV file
|
|
||||||
df = pd.read_csv(file_path)
|
|
||||||
|
|
||||||
# Ensure the 'time' column is in datetime format
|
|
||||||
df['time'] = pd.to_datetime(df['time'])
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def clean_data(df: pd.DataFrame) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Clean the historical price data by handling missing values and removing duplicates.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing historical price data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The cleaned DataFrame.
|
|
||||||
"""
|
|
||||||
# Handle missing values (if any)
|
|
||||||
df.dropna(inplace=True)
|
|
||||||
|
|
||||||
# Remove duplicate rows (if any)
|
|
||||||
df.drop_duplicates(inplace=True)
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def preprocess_data(df: pd.DataFrame, numerical_features: list = []) -> pd.DataFrame:
|
|
||||||
"""
|
|
||||||
Preprocess the historical price data by normalizing numerical features and encoding categorical features.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing historical price data.
|
|
||||||
- numerical_features (list): A list of column names corresponding to numerical features.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- pd.DataFrame: The preprocessed DataFrame.
|
|
||||||
"""
|
|
||||||
# Convert categorical features to one-hot encoding
|
|
||||||
df = pd.get_dummies(df)
|
|
||||||
|
|
||||||
# Normalize numerical features (if any)
|
|
||||||
if numerical_features:
|
|
||||||
scaler = MinMaxScaler()
|
|
||||||
df[numerical_features] = scaler.fit_transform(df[numerical_features])
|
|
||||||
|
|
||||||
return df
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
# visualization.py
|
|
||||||
"""
|
|
||||||
Module for visualizing data for the trading bot.
|
|
||||||
|
|
||||||
This module provides functions for visualizing historical price data and trade signals.
|
|
||||||
|
|
||||||
Author: Mike Kiwalabye
|
|
||||||
"""
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
def plot_price_data(df: pd.DataFrame, title: str = 'Price Chart') -> None:
|
|
||||||
"""
|
|
||||||
Plot the historical price data.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing historical price data.
|
|
||||||
- title (str): The title of the plot.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- None
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
plt.figure(figsize=(10, 6))
|
|
||||||
plt.plot(df.index, df['close'], label='Close')
|
|
||||||
|
|
||||||
# Add visualizations for other indicators, levels, and patterns
|
|
||||||
# (Add more visualizations as needed)
|
|
||||||
|
|
||||||
plt.title(title)
|
|
||||||
plt.xlabel('Time')
|
|
||||||
plt.ylabel('Price')
|
|
||||||
plt.legend()
|
|
||||||
|
|
||||||
# Use plt.show(block=True) to make the plot blocking
|
|
||||||
plt.show(block=True)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error plotting trade signals: {str(e)}")
|
|
||||||
|
|
||||||
# ...
|
|
||||||
|
|
||||||
def plot_trade_signals(df: pd.DataFrame, title: str = 'Trade Signals') -> None:
|
|
||||||
"""
|
|
||||||
Plot trade signals on the historical price chart.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- df (pd.DataFrame): The DataFrame containing historical price data with trade signals.
|
|
||||||
- title (str): The title of the plot.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- None
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
plt.figure(figsize=(10, 6))
|
|
||||||
plt.plot(df.index, df['close'], label='Close')
|
|
||||||
|
|
||||||
# Plot trade signals
|
|
||||||
buy_signals = df[df['signal'] == 'Buy']
|
|
||||||
sell_signals = df[df['signal'] == 'Sell']
|
|
||||||
|
|
||||||
plt.scatter(buy_signals.index, buy_signals['close'], color='green', marker='^', label='Buy Signal')
|
|
||||||
plt.scatter(sell_signals.index, sell_signals['close'], color='red', marker='v', label='Sell Signal')
|
|
||||||
|
|
||||||
plt.title(title)
|
|
||||||
plt.xlabel('Time')
|
|
||||||
plt.ylabel('Price')
|
|
||||||
plt.legend()
|
|
||||||
|
|
||||||
# Use plt.show(block=True) to make the plot blocking
|
|
||||||
plt.show(block=True)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error plotting trade signals: {str(e)}")
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<!-- dashboard.html -->
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Trading Dashboard</title>
|
|
||||||
|
|
||||||
<!-- Include Chart.js from a CDN -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Trading Dashboard</h1>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p><strong>Username:</strong> {{ username }}</p>
|
|
||||||
<p><strong>Account Balance:</strong> {{ account_balance }} <small>{{ account_currency }}</small></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Add a canvas element for the chart -->
|
|
||||||
<canvas id="tradeChart" width="800" height="400"></canvas>
|
|
||||||
|
|
||||||
<form action="/stop_ml_bot" method="get">
|
|
||||||
<button type="submit">Stop ML Bot</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Use a button without a form to start the ML Bot -->
|
|
||||||
<button onclick="startBot()">Start ML Bot</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Function to update the chart with new trade signals
|
|
||||||
function updateChart(tradeSignals) {
|
|
||||||
// Parse the JSON-formatted string to an object
|
|
||||||
const parsedTradeSignals = JSON.parse(tradeSignals);
|
|
||||||
|
|
||||||
// Extract relevant data for the chart (modify as needed)
|
|
||||||
const timestamps = parsedTradeSignals.map(signal => signal.time);
|
|
||||||
const prices = parsedTradeSignals.map(signal => signal.close);
|
|
||||||
|
|
||||||
// Get the canvas element
|
|
||||||
const ctx = document.getElementById('tradeChart');
|
|
||||||
|
|
||||||
// Destroy existing chart if it exists
|
|
||||||
if (ctx.chart) {
|
|
||||||
ctx.chart.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the chart
|
|
||||||
const myChart = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: timestamps,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Close Price',
|
|
||||||
data: prices,
|
|
||||||
borderColor: 'rgba(75, 192, 192, 1)',
|
|
||||||
borderWidth: 1,
|
|
||||||
fill: false
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
type: 'time',
|
|
||||||
time: {
|
|
||||||
unit: 'minute' // Adjust as needed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
beginAtZero: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Function to periodically update the chart
|
|
||||||
function periodicallyUpdateChart() {
|
|
||||||
// Fetch the latest trade signals from the server
|
|
||||||
fetch('/get_latest_trade_signals')
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(tradeSignals => {
|
|
||||||
// Update the chart with the new trade signals
|
|
||||||
updateChart(tradeSignals);
|
|
||||||
|
|
||||||
// Schedule the next update
|
|
||||||
setTimeout(periodicallyUpdateChart, 5000); // Update every 5 seconds
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error fetching trade signals:', error);
|
|
||||||
// Retry the update after an interval
|
|
||||||
setTimeout(periodicallyUpdateChart, 5000); // Retry after 5 seconds
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the initial chart update
|
|
||||||
periodicallyUpdateChart();
|
|
||||||
|
|
||||||
function startBot() {
|
|
||||||
// Send an asynchronous request to start the bot
|
|
||||||
fetch('/start_ml_bot', { method: 'POST' });
|
|
||||||
|
|
||||||
// Optionally, you can add logic here to update the UI or provide feedback to the user
|
|
||||||
console.log('Bot started!');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<!-- templates/index.html -->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>MT5 Connector</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>MetaTrader 5 Connector</h1>
|
|
||||||
<form action="/login" method="post">
|
|
||||||
<label for="username">Username:</label>
|
|
||||||
<input type="text" id="username" name="username" required><br>
|
|
||||||
|
|
||||||
<label for="password">Password:</label>
|
|
||||||
<input type="password" id="password" name="password" required><br>
|
|
||||||
|
|
||||||
<label for="server">Server:</label>
|
|
||||||
<input type="text" id="server" name="server" required><br>
|
|
||||||
|
|
||||||
<label for="path">MT5 Path:</label>
|
|
||||||
<input type="text" id="path" name="path" required><br>
|
|
||||||
|
|
||||||
<input type="submit" value="Connect">
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user