2 Commits

Author SHA1 Message Date
Mike 9f3d469f14 Made improvements to overall functionality 2023-12-01 15:49:45 +02:00
Mike f53fcb7dc3 Refactored form factor 2023-11-22 20:18:02 +02:00
22 changed files with 965 additions and 515 deletions
+3 -1
View File
@@ -1 +1,3 @@
.vscode
.vscode
.venv
__pycache__/
+29
View File
@@ -0,0 +1,29 @@
# 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"]
Executable → Regular
View File
-338
View File
@@ -1,338 +0,0 @@
from keras.optimizers import Adam
from keras.layers import Dense, Dropout
from keras.models import Sequential
import pymt5
import matplotlib.pyplot as plt
import talib
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import pandas as pd
import time
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
def connect_to_mt5_container():
server = "localhost" # Change to the appropriate IP or hostname if necessary
port = 15555 # Change to the appropriate port if necessary
login = 123456 # Change to your MetaTrader login number if necessary
password = "your_password" # Change to your MetaTrader password if necessary
# Connect to MetaTrader 5
mt5 = pymt5.PyMT5()
mt5.onConnected = onConnected
mt5.onDisconnected = onDisconnected
mt5.onData = onData
# Wait for the connection to be established
while not onConnected:
time.sleep(0.1)
# Send login request
login_request = {
'ver': '3',
'type': '1',
'login': str(login),
'password': password,
'res': '0'
}
mt5.broadcast(login_request)
# Wait for the login response
while not onConnected:
time.sleep(0.1)
# Check if login was successful
if onConnected:
print(f"Connected to MetaTrader 5: {onConnected}")
else:
print("Failed to connect to MetaTrader 5")
def onConnected(client_info):
print(f"Connected: {client_info}")
def onDisconnected(client_info):
print(f"Disconnected: {client_info}")
def onData(data):
print(f"Received data: {data}")
def start_mt5_bot():
# Define the symbols and timeframes
symbol = 'EURUSD'
timeframe = 60 # 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():
# Retrieve historical data
rates = pymt5.copy_rates_from_pos(symbol, timeframe, 0, 1000)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
df.set_index('time', inplace=True)
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'], _, df['macd_signal'] = 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):
# Implement risk management and trade execution logic based on the signals generated
# Update TensorFlow neural network model with trade outcome (loss or win)
# 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
result = pymt5.order_send(symbol, pymt5.OP_BUY, lot_size, 0, stop_loss, take_profit,
"Buy trade", 123456, pymt5.ORDER_TIME_GTC, 0)
outcome = 'Win' if result.retcode == pymt5.TRADE_RETCODE_DONE else 'Loss'
elif signal == 'Sell':
# Place a sell trade
result = pymt5.order_send(symbol, pymt5.OP_SELL, lot_size, 0, stop_loss, take_profit,
"Sell trade", 123456, pymt5.ORDER_TIME_GTC, 0)
outcome = 'Win' if result.retcode == pymt5.TRADE_RETCODE_DONE 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()
def run_trading_bot():
# Connect to MetaTrader 5 container
connect_to_mt5_container()
while True:
try:
# Get historical data
df = get_historical_data()
# 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)
# 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
# Run the trading bot
run_trading_bot()
# Load TensorFlow neural network model weights
neural_network_model.load_weights('weights/model_weights.h5')
# Disconnect from MetaTrader 5
pymt5.shutdown()
# Start the MetaTrader 5 bot
start_mt5_bot()
-30
View File
@@ -1,30 +0,0 @@
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('http://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)
+13 -51
View File
@@ -1,55 +1,17 @@
version: "3"
version: '3'
services:
metatrader_service:
trading-bot:
build:
context: .
dockerfile: docker/DockerFile.xorg
container_name: metatrader
restart: unless-stopped
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
- ./src:/app/src
- ./static:/app/static
- ./templates:/app/templates
- ./model_weights.h5:/app/model_weights.h5
environment:
- DISPLAY=$DISPLAY
privileged: true
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix
- ./mt5:/mt5
devices:
- /dev/dri:/dev/dri
ports:
- "5900:5900"
- "15555:15555"
- "15556:15556"
- "15557:15557"
- "15558:15558"
networks:
- trading_network
trading_bot:
container_name: trading_bot
build:
context: .
dockerfile: docker/DockerFile
volumes:
- ./app:/app
ports:
- 3000:3000
depends_on:
- metatrader_service
networks:
- trading_network
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
- FLASK_APP=main.py
- FLASK_RUN_HOST=0.0.0.0
- PYTHONUNBUFFERED=1
-29
View File
@@ -1,29 +0,0 @@
# 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
# Copy the application code to the container
COPY app/ .
# Run the bot script when the container launches
CMD [ "python", "bot.py" ]
-12
View File
@@ -1,12 +0,0 @@
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"]
-39
View File
@@ -1,39 +0,0 @@
# Base docker image.
FROM ubuntu:focal
# Install Wine and necessary dependencies
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
gnupg \
software-properties-common \
wget \
winbind \
xauth \
xvfb \
cabextract
# Download and install Wine from WineHQ repository
RUN wget -qO- https://dl.winehq.org/wine-builds/winehq.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/winehq.gpg && \
add-apt-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ focal main' && \
apt-get update && \
apt-get install -y --install-recommends winehq-stable winetricks
# Create a non-root user
RUN useradd -m -s /bin/bash trader
# Set the working directory
WORKDIR /home/trader
# Install X server utilities
RUN apt-get install -y x11-xserver-utils x11vnc xvfb
# Configure X server
RUN mkdir /tmp/.X11-unix && \
chown trader:trader /tmp/.X11-unix
# Set up entrypoint script
COPY mt5/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
+157
View File
@@ -0,0 +1,157 @@
"""
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)
-12
View File
@@ -1,12 +0,0 @@
#!/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
# Run MetaTrader 5
su - trader -c 'wine "/home/trader/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe"'
+5 -3
View File
@@ -1,7 +1,9 @@
numpy
# requirements.txt
pandas
numpy
scikit-learn
TA-Lib
matplotlib
scikit-learn
MetaTrader5
tensorflow
pymt5
flask
+78
View File
@@ -0,0 +1,78 @@
# 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"
+147
View File
@@ -0,0 +1,147 @@
# 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')
+254
View File
@@ -0,0 +1,254 @@
# 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)}")
+68
View File
@@ -0,0 +1,68 @@
# 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
+73
View File
@@ -0,0 +1,73 @@
# 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)}")
+110
View File
@@ -0,0 +1,110 @@
<!-- 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>
+28
View File
@@ -0,0 +1,28 @@
<!-- 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>
View File
View File