This commit is contained in:
commit
fb1a3d8581
19 changed files with 853 additions and 0 deletions
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.devcontainer
|
||||||
|
.git
|
||||||
|
docker-compose.yaml
|
||||||
|
README.md
|
||||||
|
LICENSE.md
|
||||||
|
.gitignore
|
||||||
|
.env.example
|
||||||
|
.env
|
||||||
|
config
|
||||||
4
.env.example
Normal file
4
.env.example
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
UID=1000
|
||||||
|
GID=1000
|
||||||
|
CUSTOM_USER=username
|
||||||
|
PASSWORD=securepassword
|
||||||
116
.github/workflows/docker-publish.yml
vendored
Normal file
116
.github/workflows/docker-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
name: MT5 Helm GitOps Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
tags: [ "*" ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Gleicher Registry-Prefix wie im boday_tf-Projekt
|
||||||
|
REGISTRY: localhost:3005
|
||||||
|
# Host-Header für Traefik-Ingress des Web-UI (leer = kein Ingress, kein Health-Check per HTTP)
|
||||||
|
INGRESS_HOST: mt5.local
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# HINWEIS: Terraform-Binary kommt wie bei boday_tf über das globale Runner-Volume (:ro)
|
||||||
|
|
||||||
|
- name: Trust Local Nginx Certificate Inside Container
|
||||||
|
run: |
|
||||||
|
mkdir -p /usr/local/share/ca-certificates/
|
||||||
|
cp nginx_ssl/nginx.crt /usr/local/share/ca-certificates/nginx-sandbox.crt 2>/dev/null || echo "Nutze Workspace-Zertifikat"
|
||||||
|
update-ca-certificates
|
||||||
|
|
||||||
|
# Docker verlangt Image-Namen in Kleinbuchstaben – "MetaTrader5-Docker-Image" würde sonst scheitern
|
||||||
|
- name: Compute Image Name
|
||||||
|
run: |
|
||||||
|
IMAGE="${REGISTRY}/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')"
|
||||||
|
echo "IMAGE=${IMAGE}" >> "$GITHUB_ENV"
|
||||||
|
echo "Image: ${IMAGE}"
|
||||||
|
|
||||||
|
- name: Log in to Local Registry
|
||||||
|
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ${REGISTRY} -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
# Ein Build, zwei Tags (das Image ist ~4 GB – doppelt bauen kostet unnötig Zeit)
|
||||||
|
- name: Build MT5 Image
|
||||||
|
run: |
|
||||||
|
docker build --platform linux/amd64 \
|
||||||
|
-t ${IMAGE}:${{ github.sha }} \
|
||||||
|
-t ${IMAGE}:latest \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Push MT5 Image
|
||||||
|
run: |
|
||||||
|
docker push ${IMAGE}:${{ github.sha }}
|
||||||
|
docker push ${IMAGE}:latest
|
||||||
|
|
||||||
|
- name: Prepare Kubernetes Access
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.KUBECONFIG_DATA }}" > ./kind_kubeconfig
|
||||||
|
chmod 600 ./kind_kubeconfig
|
||||||
|
|
||||||
|
# Erster Rollout kann bis 15 Min dauern (Wine + MT5 Installation nach /config)
|
||||||
|
- name: Terraform Deploy
|
||||||
|
env:
|
||||||
|
TF_VAR_vnc_password: ${{ secrets.MT5_VNC_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
terraform --version
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve \
|
||||||
|
-var="image_repository=${IMAGE}" \
|
||||||
|
-var="app_version=${{ github.sha }}" \
|
||||||
|
-var="vnc_user=${{ secrets.MT5_VNC_USER || 'trader' }}" \
|
||||||
|
-var="ingress_host=${INGRESS_HOST}"
|
||||||
|
|
||||||
|
# KasmVNC antwortet ohne Login mit 401 – daher mit Basic Auth prüfen und auf den Erststart warten
|
||||||
|
- name: Verify App Health
|
||||||
|
if: env.INGRESS_HOST != ''
|
||||||
|
env:
|
||||||
|
VNC_USER: ${{ secrets.MT5_VNC_USER || 'trader' }}
|
||||||
|
VNC_PASS: ${{ secrets.MT5_VNC_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
for i in $(seq 1 40); do
|
||||||
|
CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 \
|
||||||
|
-u "${VNC_USER}:${VNC_PASS}" -H "Host: ${INGRESS_HOST}" \
|
||||||
|
http://local-k3s-platform:80/ || true)
|
||||||
|
echo "Versuch ${i}: HTTP ${CODE}"
|
||||||
|
if [ "${CODE}" = "200" ]; then
|
||||||
|
echo "Erfolg: MetaTrader 5 Web-UI läuft via Helm im GitOps-Standard!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 15
|
||||||
|
done
|
||||||
|
echo "MT5 Web-UI nach 10 Minuten nicht erreichbar"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
# Sensible Werte (VNC-Passwort) vor dem Upload aus dem State-JSON entfernen
|
||||||
|
- name: Publish Map to cloudmon Dashboard
|
||||||
|
run: |
|
||||||
|
terraform show -json \
|
||||||
|
| jq 'del(.. | .set_sensitive?) | del(.. | .metadata? | select(type == "array") | .[]?.values?)' \
|
||||||
|
> plan.json
|
||||||
|
|
||||||
|
if grep -q "${{ secrets.MT5_VNC_PASSWORD }}" plan.json; then
|
||||||
|
echo "Abbruch: Passwort ist noch im JSON enthalten"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl --fail -X POST \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.CLOUDMON_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Host: cloudmon.local" \
|
||||||
|
--data-binary @plan.json \
|
||||||
|
"http://local-k3s-platform:80/api/v1/push/?repo=${{ github.repository }}"
|
||||||
|
|
||||||
|
echo "Infrastruktur-Map erfolgreich an cloudmon übermittelt!"
|
||||||
|
|
||||||
|
- name: Cleanup Kubeconfig
|
||||||
|
if: always()
|
||||||
|
run: rm -f ./kind_kubeconfig plan.json
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
.devcontainer/
|
||||||
|
.env
|
||||||
|
config/
|
||||||
39
Dockerfile
Normal file
39
Dockerfile
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
FROM ghcr.io/linuxserver/baseimage-kasmvnc:debianbookworm
|
||||||
|
|
||||||
|
# set version label
|
||||||
|
ARG BUILD_DATE
|
||||||
|
ARG VERSION
|
||||||
|
LABEL build_version="Metatrader Docker:- ${VERSION} Build-date:- ${BUILD_DATE}"
|
||||||
|
LABEL maintainer="gmartin"
|
||||||
|
|
||||||
|
ENV TITLE=Metatrader5
|
||||||
|
ENV WINEPREFIX="/config/.wine"
|
||||||
|
ENV WINEDEBUG=-all
|
||||||
|
|
||||||
|
# Install all packages in a single layer to reduce image size
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
python3-venv \
|
||||||
|
wget \
|
||||||
|
curl \
|
||||||
|
gnupg2 \
|
||||||
|
software-properties-common \
|
||||||
|
ca-certificates \
|
||||||
|
&& mkdir -pm755 /etc/apt/keyrings \
|
||||||
|
&& wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \
|
||||||
|
&& wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources \
|
||||||
|
&& dpkg --add-architecture i386 \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install --install-recommends -y winehq-stable \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /etc/apt/keyrings/winehq-archive.key
|
||||||
|
|
||||||
|
|
||||||
|
COPY /Metatrader /Metatrader
|
||||||
|
RUN chmod +x /Metatrader/start.sh
|
||||||
|
COPY /root /
|
||||||
|
|
||||||
|
EXPOSE 3000 8001
|
||||||
|
VOLUME /config
|
||||||
22
LICENSE.md
Normal file
22
LICENSE.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2023 Germán Martín
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
136
Metatrader/start.sh
Normal file
136
Metatrader/start.sh
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Configuration variables
|
||||||
|
mt5file='/config/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe'
|
||||||
|
WINEPREFIX='/config/.wine'
|
||||||
|
WINEDEBUG='-all'
|
||||||
|
wine_executable="wine"
|
||||||
|
metatrader_version="5.0.36"
|
||||||
|
mt5server_port="8001"
|
||||||
|
MT5_CMD_OPTIONS="${MT5_CMD_OPTIONS:-}"
|
||||||
|
mono_url="https://dl.winehq.org/wine/wine-mono/10.3.0/wine-mono-10.3.0-x86.msi"
|
||||||
|
python_url="https://www.python.org/ftp/python/3.9.13/python-3.9.13.exe"
|
||||||
|
mt5setup_url="https://download.mql5.com/cdn/web/metaquotes.software.corp/mt5/mt5setup.exe"
|
||||||
|
|
||||||
|
# Function to display a graphical message
|
||||||
|
show_message() {
|
||||||
|
echo $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if a dependency is installed
|
||||||
|
check_dependency() {
|
||||||
|
if ! command -v $1 &> /dev/null; then
|
||||||
|
echo "$1 is not installed. Please install it to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if a Python package is installed
|
||||||
|
is_python_package_installed() {
|
||||||
|
python3 -c "import pkg_resources; exit(not pkg_resources.require('$1'))" 2>/dev/null
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if a Python package is installed in Wine
|
||||||
|
is_wine_python_package_installed() {
|
||||||
|
$wine_executable python -c "import pkg_resources; exit(not pkg_resources.require('$1'))" 2>/dev/null
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for necessary dependencies
|
||||||
|
check_dependency "curl"
|
||||||
|
check_dependency "$wine_executable"
|
||||||
|
|
||||||
|
# Install Mono if not present
|
||||||
|
if [ ! -e "/config/.wine/drive_c/windows/mono" ]; then
|
||||||
|
show_message "[1/7] Downloading and installing Mono..."
|
||||||
|
curl -o /config/.wine/drive_c/mono.msi $mono_url
|
||||||
|
WINEDLLOVERRIDES=mscoree=d $wine_executable msiexec /i /config/.wine/drive_c/mono.msi /qn
|
||||||
|
rm /config/.wine/drive_c/mono.msi
|
||||||
|
show_message "[1/7] Mono installed."
|
||||||
|
else
|
||||||
|
show_message "[1/7] Mono is already installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if MetaTrader 5 is already installed
|
||||||
|
if [ -e "$mt5file" ]; then
|
||||||
|
show_message "[2/7] File $mt5file already exists."
|
||||||
|
else
|
||||||
|
show_message "[2/7] File $mt5file is not installed. Installing..."
|
||||||
|
|
||||||
|
# Set Windows 10 mode in Wine and download and install MT5
|
||||||
|
$wine_executable reg add "HKEY_CURRENT_USER\\Software\\Wine" /v Version /t REG_SZ /d "win10" /f
|
||||||
|
show_message "[3/7] Downloading MT5 installer..."
|
||||||
|
curl -o /config/.wine/drive_c/mt5setup.exe $mt5setup_url
|
||||||
|
show_message "[3/7] Installing MetaTrader 5..."
|
||||||
|
$wine_executable "/config/.wine/drive_c/mt5setup.exe" "/auto" &
|
||||||
|
wait
|
||||||
|
rm -f /config/.wine/drive_c/mt5setup.exe
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recheck if MetaTrader 5 is installed
|
||||||
|
if [ -e "$mt5file" ]; then
|
||||||
|
show_message "[4/7] File $mt5file is installed. Running MT5..."
|
||||||
|
$wine_executable "$mt5file" $MT5_CMD_OPTIONS &
|
||||||
|
else
|
||||||
|
show_message "[4/7] File $mt5file is not installed. MT5 cannot be run."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Install Python in Wine if not present
|
||||||
|
if ! $wine_executable python --version 2>/dev/null; then
|
||||||
|
show_message "[5/7] Installing Python in Wine..."
|
||||||
|
curl -L $python_url -o /tmp/python-installer.exe
|
||||||
|
$wine_executable /tmp/python-installer.exe /quiet InstallAllUsers=1 PrependPath=1
|
||||||
|
rm /tmp/python-installer.exe
|
||||||
|
show_message "[5/7] Python installed in Wine."
|
||||||
|
else
|
||||||
|
show_message "[5/7] Python is already installed in Wine."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Upgrade pip and install required packages
|
||||||
|
show_message "[6/7] Installing Python libraries"
|
||||||
|
$wine_executable python -m pip install --upgrade --no-cache-dir pip
|
||||||
|
# Install MetaTrader5 library in Windows if not installed
|
||||||
|
show_message "[6/7] Installing MetaTrader5 library in Windows"
|
||||||
|
if ! is_wine_python_package_installed "MetaTrader5==$metatrader_version"; then
|
||||||
|
$wine_executable python -m pip install --no-cache-dir MetaTrader5==$metatrader_version
|
||||||
|
fi
|
||||||
|
# Install mt5linux library in Windows if not installed
|
||||||
|
show_message "[6/7] Checking and installing mt5linux library in Windows if necessary"
|
||||||
|
if ! is_wine_python_package_installed "mt5linux"; then
|
||||||
|
$wine_executable python -m pip install --no-cache-dir "mt5linux>=0.1.9"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install python-dateutil if needed (datetime is built-in, but dateutil adds features)
|
||||||
|
if ! is_wine_python_package_installed "python-dateutil"; then
|
||||||
|
show_message "[6/7] Installing python-dateutil library in Windows"
|
||||||
|
$wine_executable python -m pip install --no-cache-dir python-dateutil
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install mt5linux library in Linux if not installed
|
||||||
|
show_message "[6/7] Checking and installing mt5linux library in Linux if necessary"
|
||||||
|
if ! is_python_package_installed "mt5linux"; then
|
||||||
|
pip install --break-system-packages --no-cache-dir --no-deps mt5linux && \
|
||||||
|
pip install --break-system-packages --no-cache-dir rpyc plumbum numpy
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install pyxdg library in Linux if not installed
|
||||||
|
show_message "[6/7] Checking and installing pyxdg library in Linux if necessary"
|
||||||
|
if ! is_python_package_installed "pyxdg"; then
|
||||||
|
pip install --break-system-packages --no-cache-dir pyxdg
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start the MT5 server on Linux
|
||||||
|
show_message "[7/7] Starting the mt5linux server..."
|
||||||
|
python3 -m mt5linux --host 0.0.0.0 -p $mt5server_port -w $wine_executable python.exe &
|
||||||
|
|
||||||
|
# Give the server some time to start
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Check if the server is running
|
||||||
|
if ss -tuln | grep ":$mt5server_port" > /dev/null; then
|
||||||
|
show_message "[7/7] The mt5linux server is running on port $mt5server_port."
|
||||||
|
else
|
||||||
|
show_message "[7/7] Failed to start the mt5linux server on port $mt5server_port."
|
||||||
|
fi
|
||||||
244
README.md
Normal file
244
README.md
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
# MetaTrader5 Docker Image
|
||||||
|
|
||||||
|
This project provides a Docker image for running MetaTrader5 with remote access via VNC, based on the [KasmVNC](https://github.com/kasmtech/KasmVNC) project and [KasmVNC Base Image from LinuxServer](https://github.com/linuxserver/docker-baseimage-kasmvnc).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Run MetaTrader5 in an isolated environment.
|
||||||
|
- Remote access to MetaTrader5 interface via an integrated VNC client accessible through a web browser.
|
||||||
|
- Built on the reliable and secure [KasmVNC](https://github.com/kasmtech/KasmVNC) project.
|
||||||
|
- RPyC server for remote access to Python MetaTrader Library from Windows or Linux using <https://github.com/lucas-campagna/mt5linux>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
**NOTICE:**
|
||||||
|
Due to some compatibility issued, version 2 has switched its base from Alpine to Debian Linux. This and adding Python environment makes that container size is considerably bigger from about 600 MB to 4 GB.
|
||||||
|
|
||||||
|
If you just need to run Metatrader for running your MQL5 programs without any Python programming I recommend to go on using version 1.0. MetaTrader program is updated independently from image so you will always have latest MT5 version.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Docker installed on your machine.
|
||||||
|
- Only intelx86/amd64 host is supported
|
||||||
|
|
||||||
|
## Usage from repository
|
||||||
|
|
||||||
|
1. Clone this repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/gmag11/MetaTrader5-Docker-Image
|
||||||
|
cd MetaTrader5-Docker-Image
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build the Docker image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t mt5 .
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the Docker image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d -p 3000:3000 -p 8001:8001 -v config:/config mt5
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can access MetaTrader5 via a web browser at localhost:3000.
|
||||||
|
|
||||||
|
On first run it may take a few minutes to get everything installed and running. Normally it takes less than 5 minutes. You don't need to do anything. All installation process is automatic and you should end up with MetaTrader5 running in your web session.
|
||||||
|
|
||||||
|
## Usage with docker compose with image form Docker Registry (preferred way)
|
||||||
|
|
||||||
|
1. Create a folder in a path where you have permission. For instance in your home.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir MT5
|
||||||
|
cd MT5
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create `docker-compose.yaml` file.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano docker-compose.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Use this content filling user and password with your own data.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mt5:
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
container_name: mt5
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
- 8001:8001
|
||||||
|
environment:
|
||||||
|
- CUSTOM_USER=<Choose a user>
|
||||||
|
- PASSWORD=<Choose a secure password>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Notice**: If you do not need to do remote python programming you can get a much smaller installation changing this line:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
```
|
||||||
|
|
||||||
|
by this one
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
image: gmag11/metatrader5_vnc:1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
**Notice**: Due to Windows permission management, if you are using windows use Docker managed volume instead of bind mount. Use this compose file instead:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
mt5:
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
container_name: mt5
|
||||||
|
volumes:
|
||||||
|
- mt5_config:/config
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
- 8001:8001
|
||||||
|
environment:
|
||||||
|
- CUSTOM_USER=<Choose a user>
|
||||||
|
- PASSWORD=<Choose a secure password>
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mt5_config:
|
||||||
|
```
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
1. Start the container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
In some systems `docker compose` command does not exists. Try to use `docker-compose up -d` instead.
|
||||||
|
|
||||||
|
4. Connect to web interface
|
||||||
|
|
||||||
|
Start your browser pointing `http://<your ip address>:3000`
|
||||||
|
|
||||||
|
On first run it may take a few minutes to get everything installed and running. Normally it takes less than 5 minutes. You don't need to do anything. All installation process is automatic and you should end up with MetaTrader5 running in your web session.
|
||||||
|
|
||||||
|
## Where to place MQ5 and EX5 files
|
||||||
|
|
||||||
|
In the case you want to run your own MQL5 bots inside the container you can find MQL5 folder structure in
|
||||||
|
|
||||||
|
```bash
|
||||||
|
config/.wine/drive_c/Program Files/MetaTrader 5/MQL5
|
||||||
|
```
|
||||||
|
|
||||||
|
All files that you place there can be accessed from your MetaTrader container without the need to restart anything.
|
||||||
|
|
||||||
|
You can access MetaEditor program clicking in `IDE` button in MetaTrader5 interface.
|
||||||
|
|
||||||
|
**Notice**: If you will run MQL5 only bots (without Python) you can run perfectly with gmag11/metatrader5_vnc:1.0 image as pointed before. Remember that **image version is not stuck to a specific MetaTrader 5 version**.
|
||||||
|
|
||||||
|
**Metatrader will always be updated automatically to latest version as it does when it is nativelly installed in Windows.**
|
||||||
|
|
||||||
|
## Python programming
|
||||||
|
|
||||||
|
You need to install [mt5linux library](https://github.com/lucas-campagna/mt5linux) in your Python host. It may be in any OS, not only Linux.
|
||||||
|
|
||||||
|
This is a simple snippet to run your Python script fron any host
|
||||||
|
|
||||||
|
```python
|
||||||
|
from mt5linux import MetaTrader5
|
||||||
|
mt5 = MetaTrader5(host='host running docker container',port=8001)
|
||||||
|
mt5.initialize()
|
||||||
|
print(mt5.version())
|
||||||
|
```
|
||||||
|
|
||||||
|
Output should be something like this:
|
||||||
|
|
||||||
|
```python
|
||||||
|
(mt5linux) linux:~/$ python3
|
||||||
|
Python 3.10.13 (main, Dec 26 2023, 20:21:41) [GCC 13.2.0] on linux
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> from mt5linux import MetaTrader5
|
||||||
|
>>> mt5 = MetaTrader5(host='192.168.1.10',port=8001)
|
||||||
|
>>> mt5.initialize()
|
||||||
|
True
|
||||||
|
>>> print(mt5.version())
|
||||||
|
(500, 4120, '22 Dec 2023')
|
||||||
|
>>>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The port configuration can be adjusted as per the instructions in the KasmVNC repository.
|
||||||
|
|
||||||
|
### MetaTrader 5 Command Line Options
|
||||||
|
|
||||||
|
You can pass command line options to MetaTrader 5 using the `MT5_CMD_OPTIONS` environment variable. This is useful for custom configurations, tester modes, or other MetaTrader command line parameters.
|
||||||
|
|
||||||
|
Example using docker-compose:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
mt5:
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
container_name: mt5
|
||||||
|
volumes:
|
||||||
|
- mt5_config:/config
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
- 8001:8001
|
||||||
|
environment:
|
||||||
|
- CUSTOM_USER=<Choose a user>
|
||||||
|
- PASSWORD=<Choose a secure password>
|
||||||
|
- MT5_CMD_OPTIONS=/config:C:\\customized_for_tester_etc.ini
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mt5_config:
|
||||||
|
```
|
||||||
|
|
||||||
|
Example using docker run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d -p 3000:3000 -p 8001:8001 \
|
||||||
|
-e MT5_CMD_OPTIONS="/config:C:\\customized_for_tester_etc.ini" \
|
||||||
|
-v mt5_config:/config \
|
||||||
|
gmag11/metatrader5_vnc
|
||||||
|
```
|
||||||
|
|
||||||
|
Common MetaTrader 5 command line options:
|
||||||
|
|
||||||
|
- `/config:<path>` - Use a specific configuration file
|
||||||
|
- `/login:<account>` - Automatically login to specified account
|
||||||
|
|
||||||
|
For a complete list of available options, refer to the [MetaTrader 5 documentation](https://www.metatrader5.com/en/terminal/help/start_advanced/start).
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Feel free to contribute to this project. All contributions are welcome. Open an issue or create a pull request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the terms of the [MIT license](https://opensource.org/license/mit/).
|
||||||
|
|
||||||
|
The [**KasmVNC**](https://github.com/kasmtech/KasmVNC) project is licensed under the [GNU General Public License v2.0 (GPLv2)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). You can check the license details of KasmVNC [here](https://github.com/kasmtech/KasmVNC/blob/master/LICENSE.TXT).
|
||||||
|
|
||||||
|
[**KasmVNC Base Image from LinuxServer**](https://github.com/linuxserver/docker-baseimage-kasmvnc) is licensed unther the GNU General Public License v3.0 (GPLv3). License is available [here](https://github.com/linuxserver/docker-baseimage-kasmvnc/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Please ensure to comply with the terms and conditions of the licenses while using or modifying this project.
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
Acknowledgments to the [KasmVNC](https://github.com/kasmtech/KasmVNC) project, [KasmVNC Base Image from LinuxServer](https://github.com/linuxserver/docker-baseimage-kasmvnc/tree/master), [mt5linux library](https://github.com/lucas-campagna/mt5linux) and any other project or individual that contributed to the realization of this project.
|
||||||
32
charts/mt5/templates/_helpers.tpl
Normal file
32
charts/mt5/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{- define "mt5.fullname" -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mt5.labels" -}}
|
||||||
|
app.kubernetes.io/name: mt5
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/version: {{ .Values.image.tag | quote }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mt5.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: mt5
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mt5.secretName" -}}
|
||||||
|
{{- if .Values.auth.existingSecret -}}
|
||||||
|
{{ .Values.auth.existingSecret }}
|
||||||
|
{{- else -}}
|
||||||
|
{{ include "mt5.fullname" . }}-auth
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mt5.claimName" -}}
|
||||||
|
{{- if .Values.persistence.existingClaim -}}
|
||||||
|
{{ .Values.persistence.existingClaim }}
|
||||||
|
{{- else -}}
|
||||||
|
{{ include "mt5.fullname" . }}-config
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
94
charts/mt5/templates/deployment.yaml
Normal file
94
charts/mt5/templates/deployment.yaml
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
# RWO-Volume + Wine-Prefix: nie zwei Pods gleichzeitig
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "mt5.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.selectorLabels" . | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||||
|
spec:
|
||||||
|
# Pod ist lange beschäftigt beim Herunterfahren von Wine
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
containers:
|
||||||
|
- name: mt5
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: {{ include "mt5.secretName" . }}
|
||||||
|
env:
|
||||||
|
- name: TZ
|
||||||
|
value: {{ .Values.tz | quote }}
|
||||||
|
- name: PUID
|
||||||
|
value: {{ .Values.puid | quote }}
|
||||||
|
- name: PGID
|
||||||
|
value: {{ .Values.pgid | quote }}
|
||||||
|
{{- if .Values.mt5CmdOptions }}
|
||||||
|
- name: MT5_CMD_OPTIONS
|
||||||
|
value: {{ .Values.mt5CmdOptions | quote }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
containerPort: 3000
|
||||||
|
protocol: TCP
|
||||||
|
- name: rpyc
|
||||||
|
containerPort: 8001
|
||||||
|
protocol: TCP
|
||||||
|
# Erststart installiert Wine/MT5 (~5 Min) – bis 15 Min Zeit geben
|
||||||
|
startupProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: web
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 90
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: web
|
||||||
|
periodSeconds: 15
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: web
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 5
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config
|
||||||
|
- name: dshm
|
||||||
|
mountPath: /dev/shm
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "mt5.claimName" . }}
|
||||||
|
{{- else }}
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
- name: dshm
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
sizeLimit: {{ .Values.shmSize }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
32
charts/mt5/templates/ingress.yaml
Normal file
32
charts/mt5/templates/ingress.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.host }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
# Nur Web-UI (KasmVNC, inkl. WebSocket) – RPyC bleibt clusterintern
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
port:
|
||||||
|
name: web
|
||||||
|
{{- end }}
|
||||||
32
charts/mt5/templates/nano
Normal file
32
charts/mt5/templates/nano
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.host }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
# Nur Web-UI (KasmVNC, inkl. WebSocket) – RPyC bleibt clusterintern
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
port:
|
||||||
|
name: web
|
||||||
|
{{- end }}
|
||||||
20
charts/mt5/templates/pvc.yaml
Normal file
20
charts/mt5/templates/pvc.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.claimName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
# PVC bei helm uninstall behalten – sonst ist Wine-Prefix + Login weg
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.persistence.accessMode }}
|
||||||
|
{{- if .Values.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.persistence.storageClass }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
15
charts/mt5/templates/secret.yaml
Normal file
15
charts/mt5/templates/secret.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{{- if not .Values.auth.existingSecret }}
|
||||||
|
{{- if not .Values.auth.password }}
|
||||||
|
{{- fail "auth.password muss gesetzt sein (oder auth.existingSecret verwenden)" }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.secretName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
CUSTOM_USER: {{ .Values.auth.user | quote }}
|
||||||
|
PASSWORD: {{ .Values.auth.password | quote }}
|
||||||
|
{{- end }}
|
||||||
19
charts/mt5/templates/service.yaml
Normal file
19
charts/mt5/templates/service.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "mt5.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "mt5.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
selector:
|
||||||
|
{{- include "mt5.selectorLabels" . | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: {{ .Values.service.webPort }}
|
||||||
|
targetPort: web
|
||||||
|
protocol: TCP
|
||||||
|
- name: rpyc
|
||||||
|
port: {{ .Values.service.rpycPort }}
|
||||||
|
targetPort: rpyc
|
||||||
|
protocol: TCP
|
||||||
14
docker-compose-windows.yaml
Normal file
14
docker-compose-windows.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
services:
|
||||||
|
mt5:
|
||||||
|
build: .
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
container_name: mt5
|
||||||
|
volumes:
|
||||||
|
- mt5-config:/config
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
- 8001:8001
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
mt5-config:
|
||||||
13
docker-compose.yaml
Normal file
13
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
services:
|
||||||
|
mt5:
|
||||||
|
build: .
|
||||||
|
image: gmag11/metatrader5_vnc
|
||||||
|
container_name: mt5
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
- 8001:8001
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
1
root/defaults/autostart
Normal file
1
root/defaults/autostart
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/Metatrader/start.sh
|
||||||
7
root/defaults/menu.xml
Normal file
7
root/defaults/menu.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openbox_menu xmlns="http://openbox.org/3.4/menu">
|
||||||
|
<menu id="root-menu" label="MENU">
|
||||||
|
<item label="xterm" icon="/usr/share/pixmaps/xterm-color_48x48.xpm"><action name="Execute"><command>/usr/bin/xterm</command></action></item>
|
||||||
|
<item label="Metatrader 5" icon="/config/.wine/drive_c/Program Files/MetaTrader 5/Terminal.ico"><action name="Execute"><command>/usr/bin/wine "/config/.wine/drive_c/Program Files/MetaTrader 5/terminal64.exe"</command></action></item>
|
||||||
|
</menu>
|
||||||
|
</openbox_menu>
|
||||||
Loading…
Reference in a new issue