diff --git a/AutoTrading_MT5_with_Logging.ipynb b/AutoTrading_MT5_with_Logging.ipynb new file mode 100644 index 0000000..b34bb94 --- /dev/null +++ b/AutoTrading_MT5_with_Logging.ipynb @@ -0,0 +1,771 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "4cb5824d", + "metadata": {}, + "outputs": [], + "source": [ + "# 📦 Imports\n", + "import MetaTrader5 as mt\n", + "import pandas as pd\n", + "import sqlite3 as db\n", + "from datetime import datetime\n", + "import time\n", + "from scipy.signal import savgol_filter\n", + "import pandas_ta as ta\n", + "import keyring as kr" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1279652c", + "metadata": {}, + "outputs": [], + "source": [ + "# 📊 Verbindung zu SQLite\n", + "def init_db(db_name=\"trading_log.db\"):\n", + " conn = db.connect(db_name)\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " CREATE TABLE IF NOT EXISTS trade_log (\n", + " timestamp TEXT,\n", + " symbol TEXT,\n", + " order_type TEXT,\n", + " price REAL,\n", + " sl REAL,\n", + " tp REAL,\n", + " volume REAL,\n", + " signal INTEGER,\n", + " comment TEXT\n", + " )\n", + " \"\"\")\n", + " conn.commit()\n", + " return conn" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "fc1eb959", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🔐 MT5 Login einmalig initialisieren\n", + "mt.initialize()\n", + "login = 10800246\n", + "server = \"VantageInternational-Demo\"\n", + "password = kr.get_password(server, str(login))\n", + "mt.login(login, password, server)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "840d41c6", + "metadata": {}, + "outputs": [], + "source": [ + "# 📥 MT5 Daten abrufen\n", + "def get_mt5_data(symbol=\"XAUUSD\", timeframe=mt.TIMEFRAME_M5, n_bars=500):\n", + " rates = mt.copy_rates_from_pos(symbol, timeframe, 0, n_bars)\n", + " df = pd.DataFrame(rates)\n", + " df[\"time\"] = pd.to_datetime(df[\"time\"], unit=\"s\")\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "48445ef4", + "metadata": {}, + "outputs": [], + "source": [ + "df = get_mt5_data()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "964f927f", + "metadata": {}, + "outputs": [], + "source": [ + "# 🤖 Signale erzeugen\n", + "def generate_signal(df):\n", + " df[\"ema10\"] = df[\"close\"].ewm(span=10).mean()\n", + " df[\"ema30\"] = df[\"close\"].ewm(span=30).mean()\n", + " df[\"rsi\"] = ta.rsi(df[\"close\"], length=14)\n", + " df[\"trend\"] = savgol_filter(df[\"close\"], 15, 3)\n", + " df[\"signal\"] = 0\n", + "\n", + " for i in range(1, len(df)):\n", + " if (\n", + " df[\"ema10\"].iloc[i] > df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] <= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] < 70\n", + " and df[\"trend\"].iloc[i] > df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = 1\n", + " elif (\n", + " df[\"ema10\"].iloc[i] < df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] >= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] > 30\n", + " and df[\"trend\"].iloc[i] < df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = -1\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7494a5da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timeopenhighlowclosetick_volumespreadreal_volumeema10ema30rsitrendsignal
02025-07-17 04:30:003340.743341.463337.213338.0412931803338.0400003338.040000NaN3338.2083860
12025-07-17 04:35:003338.033341.033337.723341.039641803339.6845003339.584833NaN3340.3778740
22025-07-17 04:40:003341.033341.483339.963341.269441803340.3178413340.180848NaN3341.8738820
32025-07-17 04:45:003341.273343.453341.273342.4710991803341.0268813340.811593NaN3342.7858600
42025-07-17 04:50:003342.473343.613342.203342.8410701803341.5473783341.273104NaN3343.2032600
..........................................
4952025-07-18 22:45:003349.293349.713348.473348.789281903350.0249623351.23273534.9351153348.4052470
4962025-07-18 22:50:003348.793348.803347.623348.158591903349.6840603351.03384932.2909093348.1866350
4972025-07-18 22:55:003348.163348.533347.653348.2510281903349.4233223350.85424533.1557603348.1533240
4982025-07-18 23:00:003348.243348.883347.723348.065991903349.1754453350.67397232.3112853348.3467440
4992025-07-18 23:05:003348.063349.253347.923348.884501903349.1217283350.55823139.4760213348.8083270
\n", + "

500 rows × 13 columns

\n", + "
" + ], + "text/plain": [ + " time open high low close tick_volume \\\n", + "0 2025-07-17 04:30:00 3340.74 3341.46 3337.21 3338.04 1293 \n", + "1 2025-07-17 04:35:00 3338.03 3341.03 3337.72 3341.03 964 \n", + "2 2025-07-17 04:40:00 3341.03 3341.48 3339.96 3341.26 944 \n", + "3 2025-07-17 04:45:00 3341.27 3343.45 3341.27 3342.47 1099 \n", + "4 2025-07-17 04:50:00 3342.47 3343.61 3342.20 3342.84 1070 \n", + ".. ... ... ... ... ... ... \n", + "495 2025-07-18 22:45:00 3349.29 3349.71 3348.47 3348.78 928 \n", + "496 2025-07-18 22:50:00 3348.79 3348.80 3347.62 3348.15 859 \n", + "497 2025-07-18 22:55:00 3348.16 3348.53 3347.65 3348.25 1028 \n", + "498 2025-07-18 23:00:00 3348.24 3348.88 3347.72 3348.06 599 \n", + "499 2025-07-18 23:05:00 3348.06 3349.25 3347.92 3348.88 450 \n", + "\n", + " spread real_volume ema10 ema30 rsi trend \\\n", + "0 18 0 3338.040000 3338.040000 NaN 3338.208386 \n", + "1 18 0 3339.684500 3339.584833 NaN 3340.377874 \n", + "2 18 0 3340.317841 3340.180848 NaN 3341.873882 \n", + "3 18 0 3341.026881 3340.811593 NaN 3342.785860 \n", + "4 18 0 3341.547378 3341.273104 NaN 3343.203260 \n", + ".. ... ... ... ... ... ... \n", + "495 19 0 3350.024962 3351.232735 34.935115 3348.405247 \n", + "496 19 0 3349.684060 3351.033849 32.290909 3348.186635 \n", + "497 19 0 3349.423322 3350.854245 33.155760 3348.153324 \n", + "498 19 0 3349.175445 3350.673972 32.311285 3348.346744 \n", + "499 19 0 3349.121728 3350.558231 39.476021 3348.808327 \n", + "\n", + " signal \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "495 0 \n", + "496 0 \n", + "497 0 \n", + "498 0 \n", + "499 0 \n", + "\n", + "[500 rows x 13 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_signal(df)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0a8abc07", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.01" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mt.symbol_info('XAUUSD').point" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64757821", + "metadata": {}, + "outputs": [], + "source": [ + "# 📤 Order senden\n", + "def send_market_order(symbol, volume, order_type, signal, conn, sl_pips=20, tp_pips=40, magic=1001):\n", + " tick = mt.symbol_info_tick(symbol)\n", + " price = tick.ask if order_type == mt.ORDER_TYPE_BUY else tick.bid\n", + " point = mt.symbol_info(symbol).point\n", + "\n", + " sl = price - sl_pips * point if order_type == mt.ORDER_TYPE_BUY else price + sl_pips * point\n", + " tp = price + tp_pips * point if order_type == mt.ORDER_TYPE_BUY else price - tp_pips * point\n", + "\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume,\n", + " \"type\": order_type,\n", + " \"price\": price,\n", + " \"sl\": round(sl, 5),\n", + " \"tp\": round(tp, 5),\n", + " \"deviation\": 20,\n", + " \"magic\": magic,\n", + " \"comment\": \"AutoSignalBot\",\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC,\n", + " }\n", + "\n", + " result = mt.order_send(request)\n", + " print(f\"[TRADE] {symbol} - {'BUY' if order_type==0 else 'SELL'} @ {price} | SL: {sl} | TP: {tp}\")\n", + "\n", + " # Logging in DB\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " INSERT INTO trade_log (timestamp, symbol, order_type, price, sl, tp, volume, signal, comment)\n", + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n", + " \"\"\", (datetime.now(), symbol, \"BUY\" if order_type==0 else \"SELL\", price, sl, tp, volume, signal, \"AutoSignalBot\"))\n", + " conn.commit()\n", + " \n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3bc5f11e", + "metadata": {}, + "outputs": [], + "source": [ + "# 🔁 Hauptfunktion\n", + "def run_live_trading(symbol=\"XAUUSD\", interval=300, volume=0.1, db_name=\"trading_log.db\"):\n", + " conn = init_db(db_name)\n", + " last_signal = 0\n", + "\n", + " print(f\"✅ Starte Auto-Trading für {symbol} – Intervall {interval}s\")\n", + " while True:\n", + " df = get_mt5_data(symbol)\n", + " df = generate_signal(df)\n", + " signal = df[\"signal\"].iloc[-1]\n", + "\n", + " if signal != 0 and signal != last_signal:\n", + " order_type = mt.ORDER_TYPE_BUY if signal == 1 else mt.ORDER_TYPE_SELL\n", + " send_market_order(symbol, volume, order_type, signal, conn)\n", + " last_signal = signal\n", + " else:\n", + " print(f\"[{datetime.now()}] Kein neues Signal ({signal})\")\n", + "\n", + " time.sleep(interval)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "71acdb0d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Starte Auto-Trading für XAUUSD – Intervall 300s\n", + "[2025-07-18 12:11:30.004688] Kein neues Signal (0)\n", + "[2025-07-18 12:16:30.083605] Kein neues Signal (0)\n", + "[2025-07-18 12:21:30.121793] Kein neues Signal (0)\n", + "[2025-07-18 12:26:30.174396] Kein neues Signal (0)\n", + "[2025-07-18 12:31:30.216996] Kein neues Signal (0)\n", + "[2025-07-18 12:36:30.258849] Kein neues Signal (0)\n", + "[2025-07-18 12:41:30.313072] Kein neues Signal (0)\n", + "[2025-07-18 12:46:30.356620] Kein neues Signal (0)\n", + "[2025-07-18 12:51:30.396600] Kein neues Signal (0)\n", + "[2025-07-18 12:56:30.442114] Kein neues Signal (0)\n", + "[2025-07-18 13:01:30.481155] Kein neues Signal (0)\n", + "[2025-07-18 13:06:30.530619] Kein neues Signal (0)\n", + "[2025-07-18 13:11:30.566248] Kein neues Signal (0)\n", + "[2025-07-18 13:16:30.606701] Kein neues Signal (0)\n", + "[2025-07-18 13:21:30.645462] Kein neues Signal (0)\n", + "[2025-07-18 13:26:30.686722] Kein neues Signal (0)\n", + "[2025-07-18 13:31:31.130100] Kein neues Signal (0)\n", + "[2025-07-18 13:36:31.193825] Kein neues Signal (0)\n", + "[2025-07-18 13:41:31.381330] Kein neues Signal (0)\n", + "[2025-07-18 13:46:31.434187] Kein neues Signal (0)\n", + "[2025-07-18 13:51:31.471695] Kein neues Signal (0)\n", + "[2025-07-18 13:56:31.507322] Kein neues Signal (0)\n", + "[2025-07-18 14:01:31.550436] Kein neues Signal (0)\n", + "[2025-07-18 14:06:31.587884] Kein neues Signal (0)\n", + "[2025-07-18 14:11:31.665002] Kein neues Signal (0)\n", + "[2025-07-18 14:16:31.704012] Kein neues Signal (0)\n", + "[2025-07-18 14:21:31.745292] Kein neues Signal (0)\n", + "[2025-07-18 14:26:31.783905] Kein neues Signal (0)\n", + "[2025-07-18 14:31:31.822325] Kein neues Signal (0)\n", + "[2025-07-18 14:36:31.873271] Kein neues Signal (0)\n", + "[2025-07-18 14:41:31.914303] Kein neues Signal (0)\n", + "[2025-07-18 14:46:31.951585] Kein neues Signal (0)\n", + "[2025-07-18 14:51:32.005271] Kein neues Signal (0)\n", + "[2025-07-18 14:56:32.046384] Kein neues Signal (0)\n", + "[2025-07-18 15:01:32.083259] Kein neues Signal (0)\n", + "[2025-07-18 15:06:32.132835] Kein neues Signal (0)\n", + "[2025-07-18 15:11:32.176714] Kein neues Signal (0)\n", + "[2025-07-18 15:16:32.221857] Kein neues Signal (0)\n", + "[2025-07-18 15:21:32.269876] Kein neues Signal (0)\n", + "[2025-07-18 15:26:32.313363] Kein neues Signal (0)\n", + "[2025-07-18 15:31:32.356954] Kein neues Signal (0)\n", + "[2025-07-18 15:36:32.403653] Kein neues Signal (0)\n", + "[2025-07-18 15:41:32.449777] Kein neues Signal (0)\n", + "[2025-07-18 15:46:32.489053] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - SELL @ 3354.56 | SL: 3354.7599999999998 | TP: 3354.16\n", + "[2025-07-18 15:56:32.609729] Kein neues Signal (0)\n", + "[2025-07-18 16:01:32.650996] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - BUY @ 3358.95 | SL: 3358.75 | TP: 3359.35\n", + "[2025-07-18 16:11:32.744972] Kein neues Signal (0)\n", + "[2025-07-18 16:16:32.791366] Kein neues Signal (0)\n", + "[2025-07-18 16:21:32.829930] Kein neues Signal (0)\n", + "[2025-07-18 16:26:32.871934] Kein neues Signal (0)\n", + "[2025-07-18 16:31:32.912571] Kein neues Signal (0)\n", + "[2025-07-18 16:36:32.954745] Kein neues Signal (0)\n", + "[2025-07-18 16:41:32.994281] Kein neues Signal (0)\n", + "[2025-07-18 16:46:33.048113] Kein neues Signal (0)\n", + "[2025-07-18 16:51:33.086281] Kein neues Signal (0)\n", + "[2025-07-18 16:56:33.127117] Kein neues Signal (0)\n", + "[2025-07-18 17:01:33.177813] Kein neues Signal (0)\n", + "[2025-07-18 17:06:33.219713] Kein neues Signal (0)\n", + "[2025-07-18 17:11:33.260138] Kein neues Signal (0)\n", + "[2025-07-18 17:16:33.302870] Kein neues Signal (0)\n", + "[2025-07-18 17:21:33.346259] Kein neues Signal (0)\n", + "[2025-07-18 17:26:33.390947] Kein neues Signal (0)\n", + "[2025-07-18 17:31:33.434736] Kein neues Signal (0)\n", + "[2025-07-18 17:36:33.476901] Kein neues Signal (0)\n", + "[2025-07-18 17:41:33.520435] Kein neues Signal (0)\n", + "[2025-07-18 17:46:33.575426] Kein neues Signal (0)\n", + "[2025-07-18 17:51:33.622573] Kein neues Signal (0)\n", + "[2025-07-18 17:56:33.662664] Kein neues Signal (0)\n", + "[2025-07-18 18:01:33.703019] Kein neues Signal (0)\n", + "[2025-07-18 18:06:33.748220] Kein neues Signal (0)\n", + "[2025-07-18 18:11:33.788812] Kein neues Signal (0)\n", + "[2025-07-18 18:16:33.827200] Kein neues Signal (0)\n", + "[2025-07-18 18:21:33.880825] Kein neues Signal (0)\n", + "[2025-07-18 18:26:33.931042] Kein neues Signal (0)\n", + "[2025-07-18 18:31:33.982017] Kein neues Signal (0)\n", + "[2025-07-18 18:36:34.021865] Kein neues Signal (1)\n", + "[2025-07-18 18:41:34.059505] Kein neues Signal (0)\n", + "[2025-07-18 18:46:34.100395] Kein neues Signal (0)\n", + "[2025-07-18 18:51:34.148794] Kein neues Signal (0)\n", + "[2025-07-18 18:56:34.186791] Kein neues Signal (0)\n", + "[2025-07-18 19:01:34.227630] Kein neues Signal (0)\n", + "[2025-07-18 19:06:34.272331] Kein neues Signal (0)\n", + "[2025-07-18 19:11:34.309122] Kein neues Signal (0)\n", + "[2025-07-18 19:16:34.350483] Kein neues Signal (0)\n", + "[2025-07-18 19:21:34.391638] Kein neues Signal (0)\n", + "[2025-07-18 19:26:34.430235] Kein neues Signal (0)\n", + "[2025-07-18 19:31:34.476827] Kein neues Signal (0)\n", + "[2025-07-18 19:36:34.516804] Kein neues Signal (0)\n", + "[2025-07-18 19:41:34.551478] Kein neues Signal (0)\n", + "[2025-07-18 19:46:34.600704] Kein neues Signal (0)\n", + "[2025-07-18 19:51:34.657098] Kein neues Signal (0)\n", + "[2025-07-18 19:56:34.694871] Kein neues Signal (0)\n", + "[2025-07-18 20:01:34.750662] Kein neues Signal (0)\n", + "[2025-07-18 20:06:34.786445] Kein neues Signal (0)\n", + "[2025-07-18 20:11:34.941510] Kein neues Signal (0)\n", + "[2025-07-18 20:16:34.997686] Kein neues Signal (0)\n", + "[2025-07-18 20:21:35.041835] Kein neues Signal (0)\n", + "[2025-07-18 20:26:35.082677] Kein neues Signal (0)\n", + "[2025-07-18 20:31:35.135303] Kein neues Signal (0)\n", + "[2025-07-18 20:36:35.174403] Kein neues Signal (0)\n", + "[2025-07-18 20:41:35.211876] Kein neues Signal (0)\n", + "[2025-07-18 20:46:35.254113] Kein neues Signal (0)\n", + "[2025-07-18 20:51:35.297650] Kein neues Signal (0)\n", + "[2025-07-18 20:56:35.338598] Kein neues Signal (0)\n", + "[2025-07-18 21:01:35.378704] Kein neues Signal (0)\n", + "[2025-07-18 21:06:35.421315] Kein neues Signal (0)\n", + "[2025-07-18 21:11:35.446675] Kein neues Signal (0)\n", + "[2025-07-18 21:16:35.501085] Kein neues Signal (0)\n", + "[2025-07-18 21:21:35.547489] Kein neues Signal (0)\n", + "[2025-07-18 21:26:35.600292] Kein neues Signal (0)\n", + "[2025-07-18 21:31:35.642080] Kein neues Signal (0)\n", + "[2025-07-18 21:36:35.681283] Kein neues Signal (0)\n", + "[2025-07-18 21:41:35.719258] Kein neues Signal (0)\n", + "[2025-07-18 21:46:35.756743] Kein neues Signal (0)\n", + "[2025-07-18 21:51:35.802329] Kein neues Signal (0)\n", + "[2025-07-18 21:56:35.849136] Kein neues Signal (0)\n", + "[2025-07-18 22:01:35.907573] Kein neues Signal (0)\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m run_live_trading(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mXAUUSD\u001b[39m\u001b[38;5;124m\"\u001b[39m, interval\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m, volume\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.1\u001b[39m)\n", + "Cell \u001b[1;32mIn[13], line 19\u001b[0m, in \u001b[0;36mrun_live_trading\u001b[1;34m(symbol, interval, volume, db_name)\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m[\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdatetime\u001b[38;5;241m.\u001b[39mnow()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m] Kein neues Signal (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00msignal\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m---> 19\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(interval)\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\n", + "run_live_trading(\"XAUUSD\", interval=300, volume=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a7675469", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timestampsymbolorder_typepricesltpvolumesignalcomment
02025-07-18 16:06:32.701648XAUUSDBUY3358.953358.753359.350.1b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'AutoSignalBot
12025-07-18 15:51:32.545794XAUUSDSELL3354.563354.763354.160.1b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff'AutoSignalBot
\n", + "
" + ], + "text/plain": [ + " timestamp symbol order_type price sl tp \\\n", + "0 2025-07-18 16:06:32.701648 XAUUSD BUY 3358.95 3358.75 3359.35 \n", + "1 2025-07-18 15:51:32.545794 XAUUSD SELL 3354.56 3354.76 3354.16 \n", + "\n", + " volume signal comment \n", + "0 0.1 b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00' AutoSignalBot \n", + "1 0.1 b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff' AutoSignalBot " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🧾 Optional: SQLite-Datenbank anzeigen\n", + "conn = db.connect(\"trading_log.db\")\n", + "pd.read_sql(\"SELECT * FROM trade_log ORDER BY timestamp DESC LIMIT 10\", conn)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4512a2c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/AutoTrading_MT5_with_Logging.ipynb:Zone.Identifier b/AutoTrading_MT5_with_Logging.ipynb:Zone.Identifier new file mode 100644 index 0000000..a45e1ac --- /dev/null +++ b/AutoTrading_MT5_with_Logging.ipynb:Zone.Identifier @@ -0,0 +1,2 @@ +[ZoneTransfer] +ZoneId=3 diff --git a/AutoTrading_MT5_with_Logging_fib_atr.ipynb b/AutoTrading_MT5_with_Logging_fib_atr.ipynb new file mode 100644 index 0000000..6f1dcd1 --- /dev/null +++ b/AutoTrading_MT5_with_Logging_fib_atr.ipynb @@ -0,0 +1,841 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "4cb5824d", + "metadata": {}, + "outputs": [], + "source": [ + "# 📦 Imports\n", + "import MetaTrader5 as mt\n", + "import pandas as pd\n", + "import sqlite3 as db\n", + "from datetime import datetime\n", + "import time\n", + "from scipy.signal import savgol_filter\n", + "import pandas_ta as ta\n", + "import keyring as kr" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1279652c", + "metadata": {}, + "outputs": [], + "source": [ + "# 📊 Verbindung zu SQLite\n", + "def init_db(db_name=\"trading_log.db\"):\n", + " conn = db.connect(db_name)\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " CREATE TABLE IF NOT EXISTS trade_log (\n", + " timestamp TEXT,\n", + " symbol TEXT,\n", + " order_type TEXT,\n", + " price REAL,\n", + " sl REAL,\n", + " tp REAL,\n", + " volume REAL,\n", + " signal INTEGER,\n", + " comment TEXT\n", + " )\n", + " \"\"\")\n", + " conn.commit()\n", + " return conn" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "fc1eb959", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🔐 MT5 Login einmalig initialisieren\n", + "mt.initialize()\n", + "login = 10800246\n", + "server = \"VantageInternational-Demo\"\n", + "password = kr.get_password(server, str(login))\n", + "mt.login(login, password, server)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "840d41c6", + "metadata": {}, + "outputs": [], + "source": [ + "# 📥 MT5 Daten abrufen\n", + "def get_mt5_data(symbol=\"XAUUSD\", timeframe=mt.TIMEFRAME_M5, n_bars=500):\n", + " rates = mt.copy_rates_from_pos(symbol, timeframe, 0, n_bars)\n", + " df = pd.DataFrame(rates)\n", + " df[\"time\"] = pd.to_datetime(df[\"time\"], unit=\"s\")\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "48445ef4", + "metadata": {}, + "outputs": [], + "source": [ + "df = get_mt5_data()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "964f927f", + "metadata": {}, + "outputs": [], + "source": [ + "# 🤖 Signale erzeugen\n", + "def generate_signal(df):\n", + " df[\"ema10\"] = df[\"close\"].ewm(span=10).mean()\n", + " df[\"ema30\"] = df[\"close\"].ewm(span=30).mean()\n", + " df[\"rsi\"] = ta.rsi(df[\"close\"], length=14)\n", + " df[\"trend\"] = savgol_filter(df[\"close\"], 15, 3)\n", + " df[\"signal\"] = 0\n", + "\n", + " for i in range(1, len(df)):\n", + " if (\n", + " df[\"ema10\"].iloc[i] > df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] <= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] < 70\n", + " and df[\"trend\"].iloc[i] > df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = 1\n", + " elif (\n", + " df[\"ema10\"].iloc[i] < df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] >= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] > 30\n", + " and df[\"trend\"].iloc[i] < df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = -1\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7494a5da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timeopenhighlowclosetick_volumespreadreal_volumeema10ema30rsitrendsignal
02025-07-17 04:30:003340.743341.463337.213338.0412931803338.0400003338.040000NaN3338.2083860
12025-07-17 04:35:003338.033341.033337.723341.039641803339.6845003339.584833NaN3340.3778740
22025-07-17 04:40:003341.033341.483339.963341.269441803340.3178413340.180848NaN3341.8738820
32025-07-17 04:45:003341.273343.453341.273342.4710991803341.0268813340.811593NaN3342.7858600
42025-07-17 04:50:003342.473343.613342.203342.8410701803341.5473783341.273104NaN3343.2032600
..........................................
4952025-07-18 22:45:003349.293349.713348.473348.789281903350.0249623351.23273534.9351153348.4052470
4962025-07-18 22:50:003348.793348.803347.623348.158591903349.6840603351.03384932.2909093348.1866350
4972025-07-18 22:55:003348.163348.533347.653348.2510281903349.4233223350.85424533.1557603348.1533240
4982025-07-18 23:00:003348.243348.883347.723348.065991903349.1754453350.67397232.3112853348.3467440
4992025-07-18 23:05:003348.063349.253347.923348.884501903349.1217283350.55823139.4760213348.8083270
\n", + "

500 rows × 13 columns

\n", + "
" + ], + "text/plain": [ + " time open high low close tick_volume \\\n", + "0 2025-07-17 04:30:00 3340.74 3341.46 3337.21 3338.04 1293 \n", + "1 2025-07-17 04:35:00 3338.03 3341.03 3337.72 3341.03 964 \n", + "2 2025-07-17 04:40:00 3341.03 3341.48 3339.96 3341.26 944 \n", + "3 2025-07-17 04:45:00 3341.27 3343.45 3341.27 3342.47 1099 \n", + "4 2025-07-17 04:50:00 3342.47 3343.61 3342.20 3342.84 1070 \n", + ".. ... ... ... ... ... ... \n", + "495 2025-07-18 22:45:00 3349.29 3349.71 3348.47 3348.78 928 \n", + "496 2025-07-18 22:50:00 3348.79 3348.80 3347.62 3348.15 859 \n", + "497 2025-07-18 22:55:00 3348.16 3348.53 3347.65 3348.25 1028 \n", + "498 2025-07-18 23:00:00 3348.24 3348.88 3347.72 3348.06 599 \n", + "499 2025-07-18 23:05:00 3348.06 3349.25 3347.92 3348.88 450 \n", + "\n", + " spread real_volume ema10 ema30 rsi trend \\\n", + "0 18 0 3338.040000 3338.040000 NaN 3338.208386 \n", + "1 18 0 3339.684500 3339.584833 NaN 3340.377874 \n", + "2 18 0 3340.317841 3340.180848 NaN 3341.873882 \n", + "3 18 0 3341.026881 3340.811593 NaN 3342.785860 \n", + "4 18 0 3341.547378 3341.273104 NaN 3343.203260 \n", + ".. ... ... ... ... ... ... \n", + "495 19 0 3350.024962 3351.232735 34.935115 3348.405247 \n", + "496 19 0 3349.684060 3351.033849 32.290909 3348.186635 \n", + "497 19 0 3349.423322 3350.854245 33.155760 3348.153324 \n", + "498 19 0 3349.175445 3350.673972 32.311285 3348.346744 \n", + "499 19 0 3349.121728 3350.558231 39.476021 3348.808327 \n", + "\n", + " signal \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "495 0 \n", + "496 0 \n", + "497 0 \n", + "498 0 \n", + "499 0 \n", + "\n", + "[500 rows x 13 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_signal(df)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0a8abc07", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.01" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mt.symbol_info('XAUUSD').point" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64757821", + "metadata": {}, + "outputs": [], + "source": [ + "# 📤 Order senden\n", + "def send_market_order(symbol, volume, order_type, signal, conn, sl_pips=20, tp_pips=40, magic=1001):\n", + " tick = mt.symbol_info_tick(symbol)\n", + " price = tick.ask if order_type == mt.ORDER_TYPE_BUY else tick.bid\n", + " point = mt.symbol_info(symbol).point\n", + "\n", + " sl = price - sl_pips * point if order_type == mt.ORDER_TYPE_BUY else price + sl_pips * point\n", + " tp = price + tp_pips * point if order_type == mt.ORDER_TYPE_BUY else price - tp_pips * point\n", + "\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume,\n", + " \"type\": order_type,\n", + " \"price\": price,\n", + " \"sl\": round(sl, 5),\n", + " \"tp\": round(tp, 5),\n", + " \"deviation\": 20,\n", + " \"magic\": magic,\n", + " \"comment\": \"AutoSignalBot\",\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC,\n", + " }\n", + "\n", + " result = mt.order_send(request)\n", + " print(f\"[TRADE] {symbol} - {'BUY' if order_type==0 else 'SELL'} @ {price} | SL: {sl} | TP: {tp}\")\n", + "\n", + " # Logging in DB\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " INSERT INTO trade_log (timestamp, symbol, order_type, price, sl, tp, volume, signal, comment)\n", + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n", + " \"\"\", (datetime.now(), symbol, \"BUY\" if order_type==0 else \"SELL\", price, sl, tp, volume, signal, \"AutoSignalBot\"))\n", + " conn.commit()\n", + " \n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3bc5f11e", + "metadata": {}, + "outputs": [], + "source": [ + "# 🔁 Hauptfunktion\n", + "def run_live_trading(symbol=\"XAUUSD\", interval=300, volume=0.1, db_name=\"trading_log.db\"):\n", + " conn = init_db(db_name)\n", + " last_signal = 0\n", + "\n", + " print(f\"✅ Starte Auto-Trading für {symbol} – Intervall {interval}s\")\n", + " while True:\n", + " df = get_mt5_data(symbol)\n", + " df = generate_signal(df)\n", + " signal = df[\"signal\"].iloc[-1]\n", + "\n", + " if signal != 0 and signal != last_signal:\n", + " order_type = mt.ORDER_TYPE_BUY if signal == 1 else mt.ORDER_TYPE_SELL\n", + " send_market_order(symbol, volume, order_type, signal, conn)\n", + " last_signal = signal\n", + " else:\n", + " print(f\"[{datetime.now()}] Kein neues Signal ({signal})\")\n", + "\n", + " time.sleep(interval)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "71acdb0d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Starte Auto-Trading für XAUUSD – Intervall 300s\n", + "[2025-07-18 12:11:30.004688] Kein neues Signal (0)\n", + "[2025-07-18 12:16:30.083605] Kein neues Signal (0)\n", + "[2025-07-18 12:21:30.121793] Kein neues Signal (0)\n", + "[2025-07-18 12:26:30.174396] Kein neues Signal (0)\n", + "[2025-07-18 12:31:30.216996] Kein neues Signal (0)\n", + "[2025-07-18 12:36:30.258849] Kein neues Signal (0)\n", + "[2025-07-18 12:41:30.313072] Kein neues Signal (0)\n", + "[2025-07-18 12:46:30.356620] Kein neues Signal (0)\n", + "[2025-07-18 12:51:30.396600] Kein neues Signal (0)\n", + "[2025-07-18 12:56:30.442114] Kein neues Signal (0)\n", + "[2025-07-18 13:01:30.481155] Kein neues Signal (0)\n", + "[2025-07-18 13:06:30.530619] Kein neues Signal (0)\n", + "[2025-07-18 13:11:30.566248] Kein neues Signal (0)\n", + "[2025-07-18 13:16:30.606701] Kein neues Signal (0)\n", + "[2025-07-18 13:21:30.645462] Kein neues Signal (0)\n", + "[2025-07-18 13:26:30.686722] Kein neues Signal (0)\n", + "[2025-07-18 13:31:31.130100] Kein neues Signal (0)\n", + "[2025-07-18 13:36:31.193825] Kein neues Signal (0)\n", + "[2025-07-18 13:41:31.381330] Kein neues Signal (0)\n", + "[2025-07-18 13:46:31.434187] Kein neues Signal (0)\n", + "[2025-07-18 13:51:31.471695] Kein neues Signal (0)\n", + "[2025-07-18 13:56:31.507322] Kein neues Signal (0)\n", + "[2025-07-18 14:01:31.550436] Kein neues Signal (0)\n", + "[2025-07-18 14:06:31.587884] Kein neues Signal (0)\n", + "[2025-07-18 14:11:31.665002] Kein neues Signal (0)\n", + "[2025-07-18 14:16:31.704012] Kein neues Signal (0)\n", + "[2025-07-18 14:21:31.745292] Kein neues Signal (0)\n", + "[2025-07-18 14:26:31.783905] Kein neues Signal (0)\n", + "[2025-07-18 14:31:31.822325] Kein neues Signal (0)\n", + "[2025-07-18 14:36:31.873271] Kein neues Signal (0)\n", + "[2025-07-18 14:41:31.914303] Kein neues Signal (0)\n", + "[2025-07-18 14:46:31.951585] Kein neues Signal (0)\n", + "[2025-07-18 14:51:32.005271] Kein neues Signal (0)\n", + "[2025-07-18 14:56:32.046384] Kein neues Signal (0)\n", + "[2025-07-18 15:01:32.083259] Kein neues Signal (0)\n", + "[2025-07-18 15:06:32.132835] Kein neues Signal (0)\n", + "[2025-07-18 15:11:32.176714] Kein neues Signal (0)\n", + "[2025-07-18 15:16:32.221857] Kein neues Signal (0)\n", + "[2025-07-18 15:21:32.269876] Kein neues Signal (0)\n", + "[2025-07-18 15:26:32.313363] Kein neues Signal (0)\n", + "[2025-07-18 15:31:32.356954] Kein neues Signal (0)\n", + "[2025-07-18 15:36:32.403653] Kein neues Signal (0)\n", + "[2025-07-18 15:41:32.449777] Kein neues Signal (0)\n", + "[2025-07-18 15:46:32.489053] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - SELL @ 3354.56 | SL: 3354.7599999999998 | TP: 3354.16\n", + "[2025-07-18 15:56:32.609729] Kein neues Signal (0)\n", + "[2025-07-18 16:01:32.650996] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - BUY @ 3358.95 | SL: 3358.75 | TP: 3359.35\n", + "[2025-07-18 16:11:32.744972] Kein neues Signal (0)\n", + "[2025-07-18 16:16:32.791366] Kein neues Signal (0)\n", + "[2025-07-18 16:21:32.829930] Kein neues Signal (0)\n", + "[2025-07-18 16:26:32.871934] Kein neues Signal (0)\n", + "[2025-07-18 16:31:32.912571] Kein neues Signal (0)\n", + "[2025-07-18 16:36:32.954745] Kein neues Signal (0)\n", + "[2025-07-18 16:41:32.994281] Kein neues Signal (0)\n", + "[2025-07-18 16:46:33.048113] Kein neues Signal (0)\n", + "[2025-07-18 16:51:33.086281] Kein neues Signal (0)\n", + "[2025-07-18 16:56:33.127117] Kein neues Signal (0)\n", + "[2025-07-18 17:01:33.177813] Kein neues Signal (0)\n", + "[2025-07-18 17:06:33.219713] Kein neues Signal (0)\n", + "[2025-07-18 17:11:33.260138] Kein neues Signal (0)\n", + "[2025-07-18 17:16:33.302870] Kein neues Signal (0)\n", + "[2025-07-18 17:21:33.346259] Kein neues Signal (0)\n", + "[2025-07-18 17:26:33.390947] Kein neues Signal (0)\n", + "[2025-07-18 17:31:33.434736] Kein neues Signal (0)\n", + "[2025-07-18 17:36:33.476901] Kein neues Signal (0)\n", + "[2025-07-18 17:41:33.520435] Kein neues Signal (0)\n", + "[2025-07-18 17:46:33.575426] Kein neues Signal (0)\n", + "[2025-07-18 17:51:33.622573] Kein neues Signal (0)\n", + "[2025-07-18 17:56:33.662664] Kein neues Signal (0)\n", + "[2025-07-18 18:01:33.703019] Kein neues Signal (0)\n", + "[2025-07-18 18:06:33.748220] Kein neues Signal (0)\n", + "[2025-07-18 18:11:33.788812] Kein neues Signal (0)\n", + "[2025-07-18 18:16:33.827200] Kein neues Signal (0)\n", + "[2025-07-18 18:21:33.880825] Kein neues Signal (0)\n", + "[2025-07-18 18:26:33.931042] Kein neues Signal (0)\n", + "[2025-07-18 18:31:33.982017] Kein neues Signal (0)\n", + "[2025-07-18 18:36:34.021865] Kein neues Signal (1)\n", + "[2025-07-18 18:41:34.059505] Kein neues Signal (0)\n", + "[2025-07-18 18:46:34.100395] Kein neues Signal (0)\n", + "[2025-07-18 18:51:34.148794] Kein neues Signal (0)\n", + "[2025-07-18 18:56:34.186791] Kein neues Signal (0)\n", + "[2025-07-18 19:01:34.227630] Kein neues Signal (0)\n", + "[2025-07-18 19:06:34.272331] Kein neues Signal (0)\n", + "[2025-07-18 19:11:34.309122] Kein neues Signal (0)\n", + "[2025-07-18 19:16:34.350483] Kein neues Signal (0)\n", + "[2025-07-18 19:21:34.391638] Kein neues Signal (0)\n", + "[2025-07-18 19:26:34.430235] Kein neues Signal (0)\n", + "[2025-07-18 19:31:34.476827] Kein neues Signal (0)\n", + "[2025-07-18 19:36:34.516804] Kein neues Signal (0)\n", + "[2025-07-18 19:41:34.551478] Kein neues Signal (0)\n", + "[2025-07-18 19:46:34.600704] Kein neues Signal (0)\n", + "[2025-07-18 19:51:34.657098] Kein neues Signal (0)\n", + "[2025-07-18 19:56:34.694871] Kein neues Signal (0)\n", + "[2025-07-18 20:01:34.750662] Kein neues Signal (0)\n", + "[2025-07-18 20:06:34.786445] Kein neues Signal (0)\n", + "[2025-07-18 20:11:34.941510] Kein neues Signal (0)\n", + "[2025-07-18 20:16:34.997686] Kein neues Signal (0)\n", + "[2025-07-18 20:21:35.041835] Kein neues Signal (0)\n", + "[2025-07-18 20:26:35.082677] Kein neues Signal (0)\n", + "[2025-07-18 20:31:35.135303] Kein neues Signal (0)\n", + "[2025-07-18 20:36:35.174403] Kein neues Signal (0)\n", + "[2025-07-18 20:41:35.211876] Kein neues Signal (0)\n", + "[2025-07-18 20:46:35.254113] Kein neues Signal (0)\n", + "[2025-07-18 20:51:35.297650] Kein neues Signal (0)\n", + "[2025-07-18 20:56:35.338598] Kein neues Signal (0)\n", + "[2025-07-18 21:01:35.378704] Kein neues Signal (0)\n", + "[2025-07-18 21:06:35.421315] Kein neues Signal (0)\n", + "[2025-07-18 21:11:35.446675] Kein neues Signal (0)\n", + "[2025-07-18 21:16:35.501085] Kein neues Signal (0)\n", + "[2025-07-18 21:21:35.547489] Kein neues Signal (0)\n", + "[2025-07-18 21:26:35.600292] Kein neues Signal (0)\n", + "[2025-07-18 21:31:35.642080] Kein neues Signal (0)\n", + "[2025-07-18 21:36:35.681283] Kein neues Signal (0)\n", + "[2025-07-18 21:41:35.719258] Kein neues Signal (0)\n", + "[2025-07-18 21:46:35.756743] Kein neues Signal (0)\n", + "[2025-07-18 21:51:35.802329] Kein neues Signal (0)\n", + "[2025-07-18 21:56:35.849136] Kein neues Signal (0)\n", + "[2025-07-18 22:01:35.907573] Kein neues Signal (0)\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m run_live_trading(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mXAUUSD\u001b[39m\u001b[38;5;124m\"\u001b[39m, interval\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m, volume\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.1\u001b[39m)\n", + "Cell \u001b[1;32mIn[13], line 19\u001b[0m, in \u001b[0;36mrun_live_trading\u001b[1;34m(symbol, interval, volume, db_name)\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m[\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdatetime\u001b[38;5;241m.\u001b[39mnow()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m] Kein neues Signal (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00msignal\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m---> 19\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(interval)\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\n", + "run_live_trading(\"XAUUSD\", interval=300, volume=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a7675469", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timestampsymbolorder_typepricesltpvolumesignalcomment
02025-07-18 16:06:32.701648XAUUSDBUY3358.953358.753359.350.1b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'AutoSignalBot
12025-07-18 15:51:32.545794XAUUSDSELL3354.563354.763354.160.1b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff'AutoSignalBot
\n", + "
" + ], + "text/plain": [ + " timestamp symbol order_type price sl tp \\\n", + "0 2025-07-18 16:06:32.701648 XAUUSD BUY 3358.95 3358.75 3359.35 \n", + "1 2025-07-18 15:51:32.545794 XAUUSD SELL 3354.56 3354.76 3354.16 \n", + "\n", + " volume signal comment \n", + "0 0.1 b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00' AutoSignalBot \n", + "1 0.1 b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff' AutoSignalBot " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🧾 Optional: SQLite-Datenbank anzeigen\n", + "conn = db.connect(\"trading_log.db\")\n", + "pd.read_sql(\"SELECT * FROM trade_log ORDER BY timestamp DESC LIMIT 10\", conn)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4512a2c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec808aea", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import numpy as np\n", + "\n", + "def calculate_fib_levels(df, lookback=20):\n", + " swing_high = df['high'].rolling(lookback).max().iloc[-1]\n", + " swing_low = df['low'].rolling(lookback).min().iloc[-1]\n", + " diff = swing_high - swing_low\n", + " levels = {\n", + " '0.0': swing_low,\n", + " '0.236': swing_high - 0.236 * diff,\n", + " '0.382': swing_high - 0.382 * diff,\n", + " '0.5': swing_high - 0.5 * diff,\n", + " '0.618': swing_high - 0.618 * diff,\n", + " '0.786': swing_high - 0.786 * diff,\n", + " '1.0': swing_high\n", + " }\n", + " return levels\n", + "\n", + "def calculate_atr(df, period=14):\n", + " df['H-L'] = df['high'] - df['low']\n", + " df['H-C'] = abs(df['high'] - df['close'].shift())\n", + " df['L-C'] = abs(df['low'] - df['close'].shift())\n", + " df['TR'] = df[['H-L', 'H-C', 'L-C']].max(axis=1)\n", + " df['ATR'] = df['TR'].rolling(period).mean()\n", + " return df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09b3f9df", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def send_fib_trade(df, symbol, order_type, volume):\n", + " fib = calculate_fib_levels(df)\n", + " df = calculate_atr(df)\n", + " atr = df['ATR'].iloc[-1]\n", + " point = mt.symbol_info(symbol).point\n", + " tick = mt.symbol_info_tick(symbol)\n", + " price = tick.ask if order_type == mt.ORDER_TYPE_BUY else tick.bid\n", + "\n", + " sl = price - atr if order_type == mt.ORDER_TYPE_BUY else price + atr\n", + " tp = price + 2 * atr if order_type == mt.ORDER_TYPE_BUY else price - 2 * atr\n", + "\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume,\n", + " \"type\": order_type,\n", + " \"price\": price,\n", + " \"sl\": round(sl, 5),\n", + " \"tp\": round(tp, 5),\n", + " \"deviation\": 20,\n", + " \"magic\": 1010,\n", + " \"comment\": \"FibATR_Trade\",\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC,\n", + " }\n", + " return mt.order_send(request)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/AutoTrading_MT5_with_Logging_fib_atr_final.ipynb b/AutoTrading_MT5_with_Logging_fib_atr_final.ipynb new file mode 100644 index 0000000..1d4fbeb --- /dev/null +++ b/AutoTrading_MT5_with_Logging_fib_atr_final.ipynb @@ -0,0 +1,885 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "4cb5824d", + "metadata": {}, + "outputs": [], + "source": [ + "# 📦 Imports\n", + "import MetaTrader5 as mt\n", + "import pandas as pd\n", + "import sqlite3 as db\n", + "from datetime import datetime\n", + "import time\n", + "from scipy.signal import savgol_filter\n", + "import pandas_ta as ta\n", + "import keyring as kr" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1279652c", + "metadata": {}, + "outputs": [], + "source": [ + "# 📊 Verbindung zu SQLite\n", + "def init_db(db_name=\"trading_log.db\"):\n", + " conn = db.connect(db_name)\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " CREATE TABLE IF NOT EXISTS trade_log (\n", + " timestamp TEXT,\n", + " symbol TEXT,\n", + " order_type TEXT,\n", + " price REAL,\n", + " sl REAL,\n", + " tp REAL,\n", + " volume REAL,\n", + " signal INTEGER,\n", + " comment TEXT\n", + " )\n", + " \"\"\")\n", + " conn.commit()\n", + " return conn" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "fc1eb959", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🔐 MT5 Login einmalig initialisieren\n", + "mt.initialize()\n", + "login = 10800246\n", + "server = \"VantageInternational-Demo\"\n", + "password = kr.get_password(server, str(login))\n", + "mt.login(login, password, server)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "840d41c6", + "metadata": {}, + "outputs": [], + "source": [ + "# 📥 MT5 Daten abrufen\n", + "def get_mt5_data(symbol=\"XAUUSD\", timeframe=mt.TIMEFRAME_M5, n_bars=500):\n", + " rates = mt.copy_rates_from_pos(symbol, timeframe, 0, n_bars)\n", + " df = pd.DataFrame(rates)\n", + " df[\"time\"] = pd.to_datetime(df[\"time\"], unit=\"s\")\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "48445ef4", + "metadata": {}, + "outputs": [], + "source": [ + "df = get_mt5_data()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "964f927f", + "metadata": {}, + "outputs": [], + "source": [ + "# 🤖 Signale erzeugen\n", + "def generate_signal(df):\n", + " df[\"ema10\"] = df[\"close\"].ewm(span=10).mean()\n", + " df[\"ema30\"] = df[\"close\"].ewm(span=30).mean()\n", + " df[\"rsi\"] = ta.rsi(df[\"close\"], length=14)\n", + " df[\"trend\"] = savgol_filter(df[\"close\"], 15, 3)\n", + " df[\"signal\"] = 0\n", + "\n", + " for i in range(1, len(df)):\n", + " if (\n", + " df[\"ema10\"].iloc[i] > df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] <= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] < 70\n", + " and df[\"trend\"].iloc[i] > df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = 1\n", + " elif (\n", + " df[\"ema10\"].iloc[i] < df[\"ema30\"].iloc[i]\n", + " and df[\"ema10\"].iloc[i - 1] >= df[\"ema30\"].iloc[i - 1]\n", + " and df[\"rsi\"].iloc[i] > 30\n", + " and df[\"trend\"].iloc[i] < df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"signal\"] = -1\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7494a5da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timeopenhighlowclosetick_volumespreadreal_volumeema10ema30rsitrendsignal
02025-07-17 04:30:003340.743341.463337.213338.0412931803338.0400003338.040000NaN3338.2083860
12025-07-17 04:35:003338.033341.033337.723341.039641803339.6845003339.584833NaN3340.3778740
22025-07-17 04:40:003341.033341.483339.963341.269441803340.3178413340.180848NaN3341.8738820
32025-07-17 04:45:003341.273343.453341.273342.4710991803341.0268813340.811593NaN3342.7858600
42025-07-17 04:50:003342.473343.613342.203342.8410701803341.5473783341.273104NaN3343.2032600
..........................................
4952025-07-18 22:45:003349.293349.713348.473348.789281903350.0249623351.23273534.9351153348.4052470
4962025-07-18 22:50:003348.793348.803347.623348.158591903349.6840603351.03384932.2909093348.1866350
4972025-07-18 22:55:003348.163348.533347.653348.2510281903349.4233223350.85424533.1557603348.1533240
4982025-07-18 23:00:003348.243348.883347.723348.065991903349.1754453350.67397232.3112853348.3467440
4992025-07-18 23:05:003348.063349.253347.923348.884501903349.1217283350.55823139.4760213348.8083270
\n", + "

500 rows × 13 columns

\n", + "
" + ], + "text/plain": [ + " time open high low close tick_volume \\\n", + "0 2025-07-17 04:30:00 3340.74 3341.46 3337.21 3338.04 1293 \n", + "1 2025-07-17 04:35:00 3338.03 3341.03 3337.72 3341.03 964 \n", + "2 2025-07-17 04:40:00 3341.03 3341.48 3339.96 3341.26 944 \n", + "3 2025-07-17 04:45:00 3341.27 3343.45 3341.27 3342.47 1099 \n", + "4 2025-07-17 04:50:00 3342.47 3343.61 3342.20 3342.84 1070 \n", + ".. ... ... ... ... ... ... \n", + "495 2025-07-18 22:45:00 3349.29 3349.71 3348.47 3348.78 928 \n", + "496 2025-07-18 22:50:00 3348.79 3348.80 3347.62 3348.15 859 \n", + "497 2025-07-18 22:55:00 3348.16 3348.53 3347.65 3348.25 1028 \n", + "498 2025-07-18 23:00:00 3348.24 3348.88 3347.72 3348.06 599 \n", + "499 2025-07-18 23:05:00 3348.06 3349.25 3347.92 3348.88 450 \n", + "\n", + " spread real_volume ema10 ema30 rsi trend \\\n", + "0 18 0 3338.040000 3338.040000 NaN 3338.208386 \n", + "1 18 0 3339.684500 3339.584833 NaN 3340.377874 \n", + "2 18 0 3340.317841 3340.180848 NaN 3341.873882 \n", + "3 18 0 3341.026881 3340.811593 NaN 3342.785860 \n", + "4 18 0 3341.547378 3341.273104 NaN 3343.203260 \n", + ".. ... ... ... ... ... ... \n", + "495 19 0 3350.024962 3351.232735 34.935115 3348.405247 \n", + "496 19 0 3349.684060 3351.033849 32.290909 3348.186635 \n", + "497 19 0 3349.423322 3350.854245 33.155760 3348.153324 \n", + "498 19 0 3349.175445 3350.673972 32.311285 3348.346744 \n", + "499 19 0 3349.121728 3350.558231 39.476021 3348.808327 \n", + "\n", + " signal \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "495 0 \n", + "496 0 \n", + "497 0 \n", + "498 0 \n", + "499 0 \n", + "\n", + "[500 rows x 13 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_signal(df)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0a8abc07", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.01" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mt.symbol_info('XAUUSD').point" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64757821", + "metadata": {}, + "outputs": [], + "source": [ + "# 📤 Order senden\n", + "def send_market_order(symbol, volume, order_type, signal, conn, sl_pips=20, tp_pips=40, magic=1001):\n", + " tick = mt.symbol_info_tick(symbol)\n", + " price = tick.ask if order_type == mt.ORDER_TYPE_BUY else tick.bid\n", + " point = mt.symbol_info(symbol).point\n", + "\n", + " sl = price - sl_pips * point if order_type == mt.ORDER_TYPE_BUY else price + sl_pips * point\n", + " tp = price + tp_pips * point if order_type == mt.ORDER_TYPE_BUY else price - tp_pips * point\n", + "\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume,\n", + " \"type\": order_type,\n", + " \"price\": price,\n", + " \"sl\": round(sl, 5),\n", + " \"tp\": round(tp, 5),\n", + " \"deviation\": 20,\n", + " \"magic\": magic,\n", + " \"comment\": \"AutoSignalBot\",\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC,\n", + " }\n", + "\n", + " result = mt.order_send(request)\n", + " print(f\"[TRADE] {symbol} - {'BUY' if order_type==0 else 'SELL'} @ {price} | SL: {sl} | TP: {tp}\")\n", + "\n", + " # Logging in DB\n", + " c = conn.cursor()\n", + " c.execute(\"\"\"\n", + " INSERT INTO trade_log (timestamp, symbol, order_type, price, sl, tp, volume, signal, comment)\n", + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n", + " \"\"\", (datetime.now(), symbol, \"BUY\" if order_type==0 else \"SELL\", price, sl, tp, volume, signal, \"AutoSignalBot\"))\n", + " conn.commit()\n", + " \n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3bc5f11e", + "metadata": {}, + "outputs": [], + "source": [ + "# 🔁 Hauptfunktion\n", + "def run_live_trading(symbol=\"XAUUSD\", interval=300, volume=0.1, db_name=\"trading_log.db\"):\n", + " conn = init_db(db_name)\n", + " last_signal = 0\n", + "\n", + " print(f\"✅ Starte Auto-Trading für {symbol} – Intervall {interval}s\")\n", + " while True:\n", + " df = get_mt5_data(symbol)\n", + " df = generate_signal(df)\n", + " signal = df[\"signal\"].iloc[-1]\n", + "\n", + " if signal != 0 and signal != last_signal:\n", + " order_type = mt.ORDER_TYPE_BUY if signal == 1 else mt.ORDER_TYPE_SELL\n", + " send_market_order(symbol, volume, order_type, signal, conn)\n", + " last_signal = signal\n", + " else:\n", + " print(f\"[{datetime.now()}] Kein neues Signal ({signal})\")\n", + "\n", + " time.sleep(interval)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "71acdb0d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Starte Auto-Trading für XAUUSD – Intervall 300s\n", + "[2025-07-18 12:11:30.004688] Kein neues Signal (0)\n", + "[2025-07-18 12:16:30.083605] Kein neues Signal (0)\n", + "[2025-07-18 12:21:30.121793] Kein neues Signal (0)\n", + "[2025-07-18 12:26:30.174396] Kein neues Signal (0)\n", + "[2025-07-18 12:31:30.216996] Kein neues Signal (0)\n", + "[2025-07-18 12:36:30.258849] Kein neues Signal (0)\n", + "[2025-07-18 12:41:30.313072] Kein neues Signal (0)\n", + "[2025-07-18 12:46:30.356620] Kein neues Signal (0)\n", + "[2025-07-18 12:51:30.396600] Kein neues Signal (0)\n", + "[2025-07-18 12:56:30.442114] Kein neues Signal (0)\n", + "[2025-07-18 13:01:30.481155] Kein neues Signal (0)\n", + "[2025-07-18 13:06:30.530619] Kein neues Signal (0)\n", + "[2025-07-18 13:11:30.566248] Kein neues Signal (0)\n", + "[2025-07-18 13:16:30.606701] Kein neues Signal (0)\n", + "[2025-07-18 13:21:30.645462] Kein neues Signal (0)\n", + "[2025-07-18 13:26:30.686722] Kein neues Signal (0)\n", + "[2025-07-18 13:31:31.130100] Kein neues Signal (0)\n", + "[2025-07-18 13:36:31.193825] Kein neues Signal (0)\n", + "[2025-07-18 13:41:31.381330] Kein neues Signal (0)\n", + "[2025-07-18 13:46:31.434187] Kein neues Signal (0)\n", + "[2025-07-18 13:51:31.471695] Kein neues Signal (0)\n", + "[2025-07-18 13:56:31.507322] Kein neues Signal (0)\n", + "[2025-07-18 14:01:31.550436] Kein neues Signal (0)\n", + "[2025-07-18 14:06:31.587884] Kein neues Signal (0)\n", + "[2025-07-18 14:11:31.665002] Kein neues Signal (0)\n", + "[2025-07-18 14:16:31.704012] Kein neues Signal (0)\n", + "[2025-07-18 14:21:31.745292] Kein neues Signal (0)\n", + "[2025-07-18 14:26:31.783905] Kein neues Signal (0)\n", + "[2025-07-18 14:31:31.822325] Kein neues Signal (0)\n", + "[2025-07-18 14:36:31.873271] Kein neues Signal (0)\n", + "[2025-07-18 14:41:31.914303] Kein neues Signal (0)\n", + "[2025-07-18 14:46:31.951585] Kein neues Signal (0)\n", + "[2025-07-18 14:51:32.005271] Kein neues Signal (0)\n", + "[2025-07-18 14:56:32.046384] Kein neues Signal (0)\n", + "[2025-07-18 15:01:32.083259] Kein neues Signal (0)\n", + "[2025-07-18 15:06:32.132835] Kein neues Signal (0)\n", + "[2025-07-18 15:11:32.176714] Kein neues Signal (0)\n", + "[2025-07-18 15:16:32.221857] Kein neues Signal (0)\n", + "[2025-07-18 15:21:32.269876] Kein neues Signal (0)\n", + "[2025-07-18 15:26:32.313363] Kein neues Signal (0)\n", + "[2025-07-18 15:31:32.356954] Kein neues Signal (0)\n", + "[2025-07-18 15:36:32.403653] Kein neues Signal (0)\n", + "[2025-07-18 15:41:32.449777] Kein neues Signal (0)\n", + "[2025-07-18 15:46:32.489053] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - SELL @ 3354.56 | SL: 3354.7599999999998 | TP: 3354.16\n", + "[2025-07-18 15:56:32.609729] Kein neues Signal (0)\n", + "[2025-07-18 16:01:32.650996] Kein neues Signal (0)\n", + "[TRADE] XAUUSD - BUY @ 3358.95 | SL: 3358.75 | TP: 3359.35\n", + "[2025-07-18 16:11:32.744972] Kein neues Signal (0)\n", + "[2025-07-18 16:16:32.791366] Kein neues Signal (0)\n", + "[2025-07-18 16:21:32.829930] Kein neues Signal (0)\n", + "[2025-07-18 16:26:32.871934] Kein neues Signal (0)\n", + "[2025-07-18 16:31:32.912571] Kein neues Signal (0)\n", + "[2025-07-18 16:36:32.954745] Kein neues Signal (0)\n", + "[2025-07-18 16:41:32.994281] Kein neues Signal (0)\n", + "[2025-07-18 16:46:33.048113] Kein neues Signal (0)\n", + "[2025-07-18 16:51:33.086281] Kein neues Signal (0)\n", + "[2025-07-18 16:56:33.127117] Kein neues Signal (0)\n", + "[2025-07-18 17:01:33.177813] Kein neues Signal (0)\n", + "[2025-07-18 17:06:33.219713] Kein neues Signal (0)\n", + "[2025-07-18 17:11:33.260138] Kein neues Signal (0)\n", + "[2025-07-18 17:16:33.302870] Kein neues Signal (0)\n", + "[2025-07-18 17:21:33.346259] Kein neues Signal (0)\n", + "[2025-07-18 17:26:33.390947] Kein neues Signal (0)\n", + "[2025-07-18 17:31:33.434736] Kein neues Signal (0)\n", + "[2025-07-18 17:36:33.476901] Kein neues Signal (0)\n", + "[2025-07-18 17:41:33.520435] Kein neues Signal (0)\n", + "[2025-07-18 17:46:33.575426] Kein neues Signal (0)\n", + "[2025-07-18 17:51:33.622573] Kein neues Signal (0)\n", + "[2025-07-18 17:56:33.662664] Kein neues Signal (0)\n", + "[2025-07-18 18:01:33.703019] Kein neues Signal (0)\n", + "[2025-07-18 18:06:33.748220] Kein neues Signal (0)\n", + "[2025-07-18 18:11:33.788812] Kein neues Signal (0)\n", + "[2025-07-18 18:16:33.827200] Kein neues Signal (0)\n", + "[2025-07-18 18:21:33.880825] Kein neues Signal (0)\n", + "[2025-07-18 18:26:33.931042] Kein neues Signal (0)\n", + "[2025-07-18 18:31:33.982017] Kein neues Signal (0)\n", + "[2025-07-18 18:36:34.021865] Kein neues Signal (1)\n", + "[2025-07-18 18:41:34.059505] Kein neues Signal (0)\n", + "[2025-07-18 18:46:34.100395] Kein neues Signal (0)\n", + "[2025-07-18 18:51:34.148794] Kein neues Signal (0)\n", + "[2025-07-18 18:56:34.186791] Kein neues Signal (0)\n", + "[2025-07-18 19:01:34.227630] Kein neues Signal (0)\n", + "[2025-07-18 19:06:34.272331] Kein neues Signal (0)\n", + "[2025-07-18 19:11:34.309122] Kein neues Signal (0)\n", + "[2025-07-18 19:16:34.350483] Kein neues Signal (0)\n", + "[2025-07-18 19:21:34.391638] Kein neues Signal (0)\n", + "[2025-07-18 19:26:34.430235] Kein neues Signal (0)\n", + "[2025-07-18 19:31:34.476827] Kein neues Signal (0)\n", + "[2025-07-18 19:36:34.516804] Kein neues Signal (0)\n", + "[2025-07-18 19:41:34.551478] Kein neues Signal (0)\n", + "[2025-07-18 19:46:34.600704] Kein neues Signal (0)\n", + "[2025-07-18 19:51:34.657098] Kein neues Signal (0)\n", + "[2025-07-18 19:56:34.694871] Kein neues Signal (0)\n", + "[2025-07-18 20:01:34.750662] Kein neues Signal (0)\n", + "[2025-07-18 20:06:34.786445] Kein neues Signal (0)\n", + "[2025-07-18 20:11:34.941510] Kein neues Signal (0)\n", + "[2025-07-18 20:16:34.997686] Kein neues Signal (0)\n", + "[2025-07-18 20:21:35.041835] Kein neues Signal (0)\n", + "[2025-07-18 20:26:35.082677] Kein neues Signal (0)\n", + "[2025-07-18 20:31:35.135303] Kein neues Signal (0)\n", + "[2025-07-18 20:36:35.174403] Kein neues Signal (0)\n", + "[2025-07-18 20:41:35.211876] Kein neues Signal (0)\n", + "[2025-07-18 20:46:35.254113] Kein neues Signal (0)\n", + "[2025-07-18 20:51:35.297650] Kein neues Signal (0)\n", + "[2025-07-18 20:56:35.338598] Kein neues Signal (0)\n", + "[2025-07-18 21:01:35.378704] Kein neues Signal (0)\n", + "[2025-07-18 21:06:35.421315] Kein neues Signal (0)\n", + "[2025-07-18 21:11:35.446675] Kein neues Signal (0)\n", + "[2025-07-18 21:16:35.501085] Kein neues Signal (0)\n", + "[2025-07-18 21:21:35.547489] Kein neues Signal (0)\n", + "[2025-07-18 21:26:35.600292] Kein neues Signal (0)\n", + "[2025-07-18 21:31:35.642080] Kein neues Signal (0)\n", + "[2025-07-18 21:36:35.681283] Kein neues Signal (0)\n", + "[2025-07-18 21:41:35.719258] Kein neues Signal (0)\n", + "[2025-07-18 21:46:35.756743] Kein neues Signal (0)\n", + "[2025-07-18 21:51:35.802329] Kein neues Signal (0)\n", + "[2025-07-18 21:56:35.849136] Kein neues Signal (0)\n", + "[2025-07-18 22:01:35.907573] Kein neues Signal (0)\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m run_live_trading(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mXAUUSD\u001b[39m\u001b[38;5;124m\"\u001b[39m, interval\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m, volume\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.1\u001b[39m)\n", + "Cell \u001b[1;32mIn[13], line 19\u001b[0m, in \u001b[0;36mrun_live_trading\u001b[1;34m(symbol, interval, volume, db_name)\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m[\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdatetime\u001b[38;5;241m.\u001b[39mnow()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m] Kein neues Signal (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00msignal\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m---> 19\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(interval)\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "# ▶️ Live-Trading starten (z. B. alle 5 Minuten)\n", + "run_live_trading(\"XAUUSD\", interval=300, volume=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a7675469", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timestampsymbolorder_typepricesltpvolumesignalcomment
02025-07-18 16:06:32.701648XAUUSDBUY3358.953358.753359.350.1b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'AutoSignalBot
12025-07-18 15:51:32.545794XAUUSDSELL3354.563354.763354.160.1b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff'AutoSignalBot
\n", + "
" + ], + "text/plain": [ + " timestamp symbol order_type price sl tp \\\n", + "0 2025-07-18 16:06:32.701648 XAUUSD BUY 3358.95 3358.75 3359.35 \n", + "1 2025-07-18 15:51:32.545794 XAUUSD SELL 3354.56 3354.76 3354.16 \n", + "\n", + " volume signal comment \n", + "0 0.1 b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00' AutoSignalBot \n", + "1 0.1 b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff' AutoSignalBot " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 🧾 Optional: SQLite-Datenbank anzeigen\n", + "conn = db.connect(\"trading_log.db\")\n", + "pd.read_sql(\"SELECT * FROM trade_log ORDER BY timestamp DESC LIMIT 10\", conn)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4512a2c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec808aea", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import numpy as np\n", + "\n", + "def calculate_fib_levels(df, lookback=20):\n", + " swing_high = df['high'].rolling(lookback).max().iloc[-1]\n", + " swing_low = df['low'].rolling(lookback).min().iloc[-1]\n", + " diff = swing_high - swing_low\n", + " levels = {\n", + " '0.0': swing_low,\n", + " '0.236': swing_high - 0.236 * diff,\n", + " '0.382': swing_high - 0.382 * diff,\n", + " '0.5': swing_high - 0.5 * diff,\n", + " '0.618': swing_high - 0.618 * diff,\n", + " '0.786': swing_high - 0.786 * diff,\n", + " '1.0': swing_high\n", + " }\n", + " return levels\n", + "\n", + "def calculate_atr(df, period=14):\n", + " df['H-L'] = df['high'] - df['low']\n", + " df['H-C'] = abs(df['high'] - df['close'].shift())\n", + " df['L-C'] = abs(df['low'] - df['close'].shift())\n", + " df['TR'] = df[['H-L', 'H-C', 'L-C']].max(axis=1)\n", + " df['ATR'] = df['TR'].rolling(period).mean()\n", + " return df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09b3f9df", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def send_fib_trade(df, symbol, order_type, volume):\n", + " fib = calculate_fib_levels(df)\n", + " df = calculate_atr(df)\n", + " atr = df['ATR'].iloc[-1]\n", + " point = mt.symbol_info(symbol).point\n", + " tick = mt.symbol_info_tick(symbol)\n", + " price = tick.ask if order_type == mt.ORDER_TYPE_BUY else tick.bid\n", + "\n", + " sl = price - atr if order_type == mt.ORDER_TYPE_BUY else price + atr\n", + " tp = price + 2 * atr if order_type == mt.ORDER_TYPE_BUY else price - 2 * atr\n", + "\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume,\n", + " \"type\": order_type,\n", + " \"price\": price,\n", + " \"sl\": round(sl, 5),\n", + " \"tp\": round(tp, 5),\n", + " \"deviation\": 20,\n", + " \"magic\": 1010,\n", + " \"comment\": \"FibATR_Trade\",\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC,\n", + " }\n", + " return mt.order_send(request)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8878e31f", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "def plot_fib_levels(df, levels):\n", + " plt.figure(figsize=(12, 6))\n", + " plt.plot(df['close'], label='Close Price', alpha=0.5)\n", + " last_index = df.index[-1]\n", + " start_index = df.index[-50] if len(df) >= 50 else df.index[0]\n", + "\n", + " for level, price in levels.items():\n", + " plt.hlines(price, start_index, last_index, label=f'Fibo {level}: {round(price, 2)}', linestyles='--')\n", + "\n", + " plt.title(\"Fibonacci Retracement Levels\")\n", + " plt.xlabel(\"Zeit\")\n", + " plt.ylabel(\"Preis\")\n", + " plt.legend()\n", + " plt.grid(True)\n", + " plt.tight_layout()\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffa9c58a", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def check_fib_entry(df, fib_levels, tolerance=0.01):\n", + " current_price = df['close'].iloc[-1]\n", + " level_price = fib_levels['0.382']\n", + " diff = abs(current_price - level_price)\n", + " fib_range = fib_levels['1.0'] - fib_levels['0.0']\n", + " return diff < tolerance * fib_range\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Backtest_5minXAUUSD.py b/Backtest_5minXAUUSD.py new file mode 100644 index 0000000..4e7d69e --- /dev/null +++ b/Backtest_5minXAUUSD.py @@ -0,0 +1,66 @@ +import pandas as pd +import numpy as np +from backtesting import Backtest, Strategy +from backtesting.lib import crossover +from ta.momentum import rsi +from scipy.signal import savgol_filter + +# Daten vorbereiten (df muss OHLCV-Daten enthalten: 'open', 'high', 'low', 'close', 'volume') +df = pd.read_csv('xauusd_5min.csv', parse_dates=['time']) +df.set_index('time', inplace=True) + +# Indikatoren berechnen +def calculate_indicators(df): + df['ema21'] = df['close'].ewm(span=21).mean() + df['ema50'] = df['close'].ewm(span=50).mean() + df['rsi9'] = rsi(df['close'], length=9) + df['rsi14'] = rsi(df['close'], length=14) + df['trend'] = savgol_filter(df['close'], window_length=25, polyorder=3) + return df + +df = calculate_indicators(df) + +# Strategie definieren +class Gold5MinStrategy(Strategy): + def init(self): + # Indikatoren für den Plot + self.add_indicator('EMA21', self.data.ema21) + self.add_indicator('EMA50', self.data.ema50) + + def next(self): + current_index = len(self.data.close) - 1 + + # Long-Signal (Kauf) + if ( + crossover(self.data.ema21, self.data.ema50) + and self.data.rsi14[-1] < 65 + and self.data.rsi9[-1] > 50 + and self.data.trend[-1] > self.data.trend[-2] + and not self.position.is_long + ): + self.buy(sl=self.data.low[-1] * 0.995, tp=self.data.close[-1] * 1.01) # 0.5% SL, 1% TP + + # Short-Signal (Verkauf) + elif ( + crossover(self.data.ema50, self.data.ema21) + and self.data.rsi14[-1] > 35 + and self.data.rsi9[-1] < 50 + and self.data.trend[-1] < self.data.trend[-2] + and not self.position.is_short + ): + self.sell(sl=self.data.high[-1] * 1.005, tp=self.data.close[-1] * 0.99) # 0.5% SL, 1% TP + +# Backtest ausführen +bt = Backtest(df, Gold5MinStrategy, commission=0.0002, margin=0.05) # 0.02% Kommission, 5% Margin +stats = bt.run() +print(stats) + +# Optimierung (optional) +# stats_opt = bt.optimize( +# rsi_long_upper=[60, 65, 70], +# rsi_short_lower=[30, 35, 40], +# maximize='Return [%]' +# ) + +# Ergebnisse plotten +bt.plot() \ No newline at end of file diff --git a/TradingBot_V1.1.ipynb b/TradingBot_V1.1.ipynb new file mode 100644 index 0000000..53ce238 --- /dev/null +++ b/TradingBot_V1.1.ipynb @@ -0,0 +1,2466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Import Libaries" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install ta_lib-0.6.5-cp311-cp311-win_amd64.whl" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#%pip install talib" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install ta\n", + "from ta.trend import ADXIndicator, EMAIndicator\n", + "from ta.momentum import RSIIndicator\n", + "from talib import CDLHAMMER, CDLSHOOTINGSTAR" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import mplfinance as mpf\n", + "import keyring as kr\n", + "import MetaTrader5 as mt\n", + "import requests\n", + "import re\n", + "from time import sleep\n", + "import sqlite3 as db\n", + "#import matplotlib.pyplot as plt\n", + "import pandas_ta as ta\n", + "import numpy as np\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from scipy.signal import savgol_filter\n", + "from scipy.signal import find_peaks\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Login" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# login to your Trading Account - sign up in the description\n", + "mt.initialize()\n", + " \n", + "login = 10800246\n", + "server = 'VantageInternational-Demo'\n", + "password = kr.get_password(server, str(login))\n", + "\n", + "\n", + "mt.login(login, password, server)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'trading-demo'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "project = \"trading-\" + server[-4::1]\n", + "project = project.lower()\n", + "project" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Set symbol and volume" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "pause_trading = 0\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "symbols = ['XAUUSD']\n", + "#symbols = ['BTCUSD']\n", + "\n", + "#'BTCUSD', 'ETHUSD', \n", + " #'XRPUSD', , 'EURNZD', 'EURUSD'" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "volume_dict = {\n", + " 'BTCUSD' : 0.1,\n", + " 'BTCUSD_short' : 0.1,\n", + "\n", + " 'ETHUSD' : 1.0,\n", + " 'ETHUSD_short' : 1.0,\n", + " \n", + " 'XRPUSD': 0.1,\n", + " 'XRPUSD_short': 0.1,\n", + "\n", + " 'XAUUSD': 0.1,\n", + " 'XAUUSD_short': 0.1,\n", + "\n", + " 'EURUSD': 0.1,\n", + " 'EURUSD_short': 0.1,\n", + "\n", + " 'EURNZD': 0.1,\n", + " 'EURNZD_short': 0.1,\n", + "\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "periods_dict = {\n", + " 'BTCUSD' : ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " \n", + " 'ETHUSD' : ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + "\n", + " \n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " \n", + " 'XAUUSD': [ 'm15'],\n", + "\n", + " \n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + "\n", + "\n", + " 'EURNZD': ['m5', 'm2', 'm1'],\n", + "\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def get_symbol():\n", + " global symbols, pause_trading, periods_dict\n", + " pricemovement = {}\n", + "\n", + " for s in symbols:\n", + " items = mt.symbol_info(s)\n", + " pricemovement[s] = round(items.price_change,2)\n", + " #print(s, round(items.price_change,2))\n", + "\n", + " #percentage = pricemovement[max(pricemovement, key=pricemovement.get)]\n", + " #symbol = max(pricemovement, key=pricemovement.get)\n", + " #volume = volume_dict[symbol]\n", + "\n", + " sorted_pricemovement = sorted(pricemovement.items(), key=lambda x:x[1], reverse=True)\n", + " converted_dict = dict(sorted_pricemovement)\n", + "\n", + " print(converted_dict)\n", + "\n", + " percentage = converted_dict[max(converted_dict, key=converted_dict.get)]\n", + " symbol = max(converted_dict, key=converted_dict.get)\n", + " volume = volume_dict[symbol]\n", + "\n", + "\n", + " print(symbol, percentage, volume)\n", + " # if percentage > 0: # and percentage < 0.8:\n", + " # periods_dict[symbol] = ['m15', 'm5', 'm2', 'm1']\n", + " # elif percentage > 0.8:\n", + " # periods_dict[symbol] = ['h1', 'm30', 'm15', 'm5', 'm1']\n", + "\n", + " #\n", + "\n", + " #print(periods_dict)\n", + "\n", + " # if percentage > 0 and mt.positions_total() == 0:\n", + " # pause_trading = 0 #0 no puase\n", + " # return symbol, percentage, volume, periods_dict\n", + " # elif percentage < 0.1 and mt.positions_total() == 0:\n", + " # print(\"aktuell kein neues Symbol, pause Trading\")\n", + " # pause_trading = 1 #1 pause\n", + " # return None\n", + "\n", + " return symbol, percentage, volume, periods_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 1.08}\n", + "XAUUSD 1.08 0.1\n" + ] + }, + { + "data": { + "text/plain": [ + "('XAUUSD',\n", + " 1.08,\n", + " 0.1,\n", + " {'BTCUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'ETHUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XAUUSD': ['m15'],\n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'EURNZD': ['m5', 'm2', 'm1']})" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_symbol()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def set_symbol():\n", + " global symbol, volume, volume_dict\n", + " symb = get_symbol()\n", + " if symb != None:\n", + " symbol = symb[0]\n", + " volume = volume_dict[symb[0]]\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## set volume manuell" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 1.08}\n", + "XAUUSD 1.08 0.1\n" + ] + }, + { + "data": { + "text/plain": [ + "('XAUUSD',\n", + " 1.08,\n", + " 0.1,\n", + " {'BTCUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'ETHUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XAUUSD': ['m15'],\n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'EURNZD': ['m5', 'm2', 'm1']})" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_symbol()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 1.08}\n", + "XAUUSD 1.08 0.1\n" + ] + } + ], + "source": [ + "set_symbol()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('XAUUSD', 0.1, 0)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "symbol, volume, pause_trading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Functions to place Orders on Market" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pos = mt.positions_get()\n", + "for i in pos:\n", + " #if i.comment == 'Retracement Bot':\n", + " # print(i.ticket)\n", + "\n", + " if bool(re.search('^BuyStop[0-9]{2}', i.comment)):\n", + " print(i.ticket)\n", + "\n", + "mt.positions_total()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Retracement Bot\n", + "(TradePosition(ticket=382221755, time=1756930501, time_msc=1756930501001, time_update=1756930501, time_update_msc=1756930501001, type=0, magic=30, identifier=382221755, reason=3, volume=0.1, price_open=3572.38, sl=3569.69, tp=3580.45, price_current=3572.1, swap=0.0, profit=-2.8, symbol='XAUUSD', comment='Retracement Bot', external_id=''),)\n" + ] + } + ], + "source": [ + "strategy_name = 'Retracement Bot'\n", + "pos = mt.positions_get()\n", + "for p in pos:\n", + " if p.comment == strategy_name:\n", + " print(p.comment)\n", + "print(pos)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Market Order Function" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def market_order(symbol, volume, order_type, deviation=20, magic=30, stoploss=0.0, take_profit=0.0,\n", + " strategy_name='Retracement Bot'):\n", + "\n", + " global project, pause_trading\n", + "\n", + " project_id_dict = {\n", + " 'trading-demo': 'a3f3ae',\n", + " 'trading-live': '747543'\n", + " }\n", + "\n", + " order_type_dict = {\n", + " 'buy': mt.ORDER_TYPE_BUY,\n", + " 'sell': mt.ORDER_TYPE_SELL\n", + " }\n", + "\n", + " price_dict = {\n", + " 'buy': mt.symbol_info_tick(symbol).ask,\n", + " 'sell': mt.symbol_info_tick(symbol).bid\n", + " }\n", + "\n", + " buypos = []\n", + "\n", + " pos = mt.positions_get()\n", + " for p in pos:\n", + " if p.comment == strategy_name:\n", + " buypos.append('true')\n", + " \n", + " activepos = buypos.count('true')\n", + "\n", + " if order_type == 'buy' and activepos == 0 and pause_trading == 0: # and mt.positions_total() == 0:\n", + " \n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume, # FLOAT\n", + " \"type\": order_type_dict[order_type],\n", + " \"price\": price_dict[order_type],\n", + " \"sl\": stoploss, # FLOAT\n", + " \"tp\": take_profit, # FLOAT\n", + " \"deviation\": deviation, # INTERGER\n", + " \"magic\": magic, # INTERGER\n", + " \"comment\": strategy_name,\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC, # mt.ORDER_FILLING_FOK if IOC does not work\n", + " }\n", + "\n", + " requests.post('https://api.mynotifier.app', {\n", + " \"apiKey\": 'beafb52e-3cb6-477a-92ef-2f10bff50e20',\n", + " \"message\": \"Es wrude ein Handel eröffnet!\",\n", + " \"description\": \"Bitte kontrolliere die Position\",\n", + " \"type\": \"info\",#\"info\", # info, error, warning or success\n", + " \"project\": project_id_dict[project]\n", + " })\n", + "\n", + " order_result = mt.order_send(request)\n", + " #return (order_result)\n", + " \n", + " elif order_type == 'sell' and mt.positions_total() > 0:\n", + " pos = mt.positions_get()\n", + " for p in pos:\n", + " if p.comment == strategy_name:\n", + " # while schleife ?\n", + " positions = mt.positions_get()\n", + " ticket = p.ticket\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume, # FLOAT\n", + " \"type\": order_type_dict[order_type],\n", + " \"price\": price_dict[order_type],\n", + " \"position\": ticket,\n", + " \"sl\": stoploss, # FLOAT\n", + " \"tp\": take_profit, # FLOAT\n", + " \"deviation\": deviation, # INTERGER\n", + " \"magic\": magic, # INTERGER\n", + " \"comment\": strategy_name,\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC, # mt.ORDER_FILLING_FOK if IOC does not work\n", + " }\n", + "\n", + " requests.post('https://api.mynotifier.app', {\n", + " \"apiKey\": 'beafb52e-3cb6-477a-92ef-2f10bff50e20',\n", + " \"message\": \"Es wrude ein Handel geschlossen!\",\n", + " \"description\": \"Bitte prüfe die Position\",\n", + " \"type\": \"info\",#\"info\", # info, error, warning or success\n", + " \"project\": project_id_dict[project]\n", + " })\n", + "\n", + " order_result = mt.order_send(request)\n", + " #return (order_result)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trend Detection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## timefame & trend dictionary" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "debug = False" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "trend_dict = {\n", + " #'m5': '',\n", + " #'m10': '',\n", + " 'm15': '',\n", + " #'m30': '',\n", + " #'h4': '',\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "timeframes_dict = {\n", + " 'm1': mt.TIMEFRAME_M1,\n", + " 'm2': mt.TIMEFRAME_M2,\n", + " 'm3': mt.TIMEFRAME_M3,\n", + " 'm5': mt.TIMEFRAME_M5,\n", + " 'm15': mt.TIMEFRAME_M15,\n", + " 'm20': mt.TIMEFRAME_M20,\n", + " 'm30': mt.TIMEFRAME_M30,\n", + " 'h1': mt.TIMEFRAME_H1,\n", + " 'h4': mt.TIMEFRAME_H4,\n", + " 'd1': mt.TIMEFRAME_D1,\n", + "}\n", + "\n", + "\n", + "# timeframes = {\n", + "# 'm1': mt.TIMEFRAME_M1,\n", + "# 'm2': mt.TIMEFRAME_M2,\n", + "# 'm3': mt.TIMEFRAME_M3,\n", + "# 'm5': mt.TIMEFRAME_M5,\n", + "# 'm15': mt.TIMEFRAME_M15,\n", + "# 'm20': mt.TIMEFRAME_M20,\n", + "# 'm30': mt.TIMEFRAME_M30,\n", + "# 'h1': mt.TIMEFRAME_H1,\n", + "# }" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'m15': ''}\n" + ] + } + ], + "source": [ + "print(trend_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "def get_rates(periode, bars=300):\n", + " #global symbol\n", + "\n", + " # OHLC abrufen\n", + " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[periode], 0, bars)\n", + " df = pd.DataFrame(ohlc)\n", + " df['time'] = pd.to_datetime(df['time'], unit='s')\n", + "\n", + " # Umwandeln in float\n", + " df[\"open\"] = df[\"open\"].astype(float)\n", + " df[\"high\"] = df[\"high\"].astype(float)\n", + " df[\"low\"] = df[\"low\"].astype(float)\n", + " df[\"close\"] = df[\"close\"].astype(float)\n", + "\n", + " # ATR berechnen (klassisch 14)\n", + " df[\"atr\"] = ta.atr(high=df[\"high\"], low=df[\"low\"], close=df[\"close\"], length=14)\n", + "\n", + " # leichte Glättung (optional, um Rauschen zu reduzieren)\n", + " df[\"atr\"] = df[\"atr\"].rolling(window=5).mean()\n", + "\n", + " # Index setzen\n", + " df.set_index(\"time\", inplace=True)\n", + "\n", + " # NaNs entfernen (anfangs durch ATR-Berechnung)\n", + " df = df.dropna()\n", + "\n", + " return df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
openhighlowclosetick_volumespreadreal_volumeatr
time
2025-07-23 16:00:003419.983420.523381.473387.388969219013.861980
2025-07-23 20:00:003387.333395.943385.743386.784953419014.128410
2025-07-24 00:00:003388.013393.163386.483391.441849619014.305667
2025-07-24 04:00:003391.443393.363374.713382.575631519014.547405
2025-07-24 08:00:003382.563382.923365.823369.685466319014.818019
...........................
2025-09-03 04:00:003536.073545.893529.363536.815969720018.731740
2025-09-03 08:00:003536.823541.193526.933539.995847620019.107330
2025-09-03 12:00:003540.043551.433532.293550.566300020019.007235
2025-09-03 16:00:003550.603572.573549.383572.438737520018.985718
2025-09-03 20:00:003572.453572.983570.243572.12442820018.713310
\n", + "

182 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " open high low close tick_volume spread \\\n", + "time \n", + "2025-07-23 16:00:00 3419.98 3420.52 3381.47 3387.38 89692 19 \n", + "2025-07-23 20:00:00 3387.33 3395.94 3385.74 3386.78 49534 19 \n", + "2025-07-24 00:00:00 3388.01 3393.16 3386.48 3391.44 18496 19 \n", + "2025-07-24 04:00:00 3391.44 3393.36 3374.71 3382.57 56315 19 \n", + "2025-07-24 08:00:00 3382.56 3382.92 3365.82 3369.68 54663 19 \n", + "... ... ... ... ... ... ... \n", + "2025-09-03 04:00:00 3536.07 3545.89 3529.36 3536.81 59697 20 \n", + "2025-09-03 08:00:00 3536.82 3541.19 3526.93 3539.99 58476 20 \n", + "2025-09-03 12:00:00 3540.04 3551.43 3532.29 3550.56 63000 20 \n", + "2025-09-03 16:00:00 3550.60 3572.57 3549.38 3572.43 87375 20 \n", + "2025-09-03 20:00:00 3572.45 3572.98 3570.24 3572.12 4428 20 \n", + "\n", + " real_volume atr \n", + "time \n", + "2025-07-23 16:00:00 0 13.861980 \n", + "2025-07-23 20:00:00 0 14.128410 \n", + "2025-07-24 00:00:00 0 14.305667 \n", + "2025-07-24 04:00:00 0 14.547405 \n", + "2025-07-24 08:00:00 0 14.818019 \n", + "... ... ... \n", + "2025-09-03 04:00:00 0 18.731740 \n", + "2025-09-03 08:00:00 0 19.107330 \n", + "2025-09-03 12:00:00 0 19.007235 \n", + "2025-09-03 16:00:00 0 18.985718 \n", + "2025-09-03 20:00:00 0 18.713310 \n", + "\n", + "[182 rows x 8 columns]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_rates('h4', 200)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Wirkung |\n", + "| ------------ | ------------------------------------------- |\n", + "| `distance` | Wie **nah beieinander** Peaks liegen dürfen |\n", + "| `width` | Wie **breit/flach** ein Peak sein muss |\n", + "| `prominence` | Wie **stark auffällig** ein Peak sein muss |\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "def get_trend(timeframe=\"h4\", lookback=150):\n", + " \"\"\"\n", + " Bestimme Trendrichtung per Linear Regression.\n", + " Liefert:\n", + " - trend: \"uptrend\" / \"downtrend\" / \"sideways\"\n", + " - slope: numerischer Wert der Regression\n", + " - atr: ATR des Zeitraums\n", + " - slope_threshold: dynamische Schwelle für Seitwärtsbewegungen\n", + " \"\"\"\n", + " df = get_rates(timeframe, lookback)\n", + " if df.empty:\n", + " return {\"trend\": \"sideways\", \"slope\": 0, \"atr\": 0, \"slope_threshold\": 0}\n", + "\n", + " # Linear Regression\n", + " X = np.arange(len(df)).reshape(-1, 1)\n", + " y = df[\"close\"].values.reshape(-1, 1)\n", + " slope = LinearRegression().fit(X, y).coef_[0][0]\n", + "\n", + " # ATR\n", + " df[\"hl\"] = df[\"high\"] - df[\"low\"]\n", + " df[\"hc\"] = (df[\"high\"] - df[\"close\"].shift()).abs()\n", + " df[\"lc\"] = (df[\"low\"] - df[\"close\"].shift()).abs()\n", + " df[\"tr\"] = df[[\"hl\",\"hc\",\"lc\"]].max(axis=1)\n", + " atr = df[\"tr\"].rolling(14).mean().iloc[-1]\n", + "\n", + " slope_threshold = (atr / df[\"close\"].iloc[-1]) * 1.2\n", + "\n", + " if abs(slope) < slope_threshold:\n", + " trend = \"sideways\"\n", + " else:\n", + " trend = \"uptrend\" if slope > 0 else \"downtrend\"\n", + "\n", + " return {\n", + " \"trend\": trend,\n", + " \"slope\": slope,\n", + " \"atr\": atr,\n", + " \"slope_threshold\": slope_threshold\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "def get_top_down_signal(symbol=symbol):\n", + " \"\"\"\n", + " Top-Down Ansatz:\n", + " - D1 / H4: Trend bestimmen\n", + " - H1 / M30: Setup identifizieren\n", + " - M15 / M5: Einstiege optimieren (Signale ohne Tradeausführung)\n", + " \"\"\"\n", + " global trend_dict\n", + "\n", + " # --- Höhere Timeframes ---\n", + " d1_trend_info = get_trend(\"d1\", lookback=200)\n", + " h4_trend_info = get_trend(\"h4\", lookback=150)\n", + "\n", + " # --- Mittlere Timeframes für Setups ---\n", + " h1_trend_info = get_trend(\"h1\", lookback=100)\n", + " m30_trend_info = get_trend(\"m30\", lookback=60)\n", + "\n", + " # --- Niedrigere Timeframes für Einstiege (nur Signal, kein Trade) ---\n", + " m15_trend_info = get_trend(\"m15\", lookback=50)\n", + " m5_trend_info = get_trend(\"m5\", lookback=20)\n", + "\n", + " # --- Konsolidierte Trendanalyse ---\n", + " top_down_trend = \"sideways\"\n", + " if d1_trend_info[\"trend\"] == h4_trend_info[\"trend\"]:\n", + " top_down_trend = d1_trend_info[\"trend\"]\n", + "\n", + " # --- Setup-Bedingungen ---\n", + " setup_ready = False\n", + " if top_down_trend != \"sideways\":\n", + " if h1_trend_info[\"trend\"] == top_down_trend and m30_trend_info[\"trend\"] == top_down_trend:\n", + " setup_ready = True\n", + "\n", + " # --- Einstiegsberechnung ---\n", + " entry_signal = 0\n", + " if setup_ready:\n", + " if m15_trend_info[\"trend\"] == top_down_trend and m5_trend_info[\"trend\"] == top_down_trend:\n", + " entry_signal = 1 if top_down_trend == \"uptrend\" else -1\n", + "\n", + " # --- Speichern ---\n", + " trend_dict[\"top_down\"] = {\n", + " \"D1\": d1_trend_info,\n", + " \"H4\": h4_trend_info,\n", + " \"H1\": h1_trend_info,\n", + " \"M30\": m30_trend_info,\n", + " \"M15\": m15_trend_info,\n", + " \"M5\": m5_trend_info,\n", + " \"top_down_trend\": top_down_trend,\n", + " \"setup_ready\": setup_ready,\n", + " \"entry_signal\": entry_signal\n", + " }\n", + "\n", + " return trend_dict[\"top_down\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'trend': 'uptrend',\n", + " 'slope': 1.4477744934856227,\n", + " 'atr': 9.130714285714314,\n", + " 'slope_threshold': 0.0030673261656543383}" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_trend(\"h1\")" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'D1': {'trend': 'uptrend',\n", + " 'slope': 4.621913228515892,\n", + " 'atr': 39.36499999999988,\n", + " 'slope_threshold': 0.013270331238569827},\n", + " 'H4': {'trend': 'uptrend',\n", + " 'slope': 0.8813408347377812,\n", + " 'atr': 20.499285714285698,\n", + " 'slope_threshold': 0.006910512170269389},\n", + " 'H1': {'trend': 'uptrend',\n", + " 'slope': 1.8054590176423853,\n", + " 'atr': 9.649999999999993,\n", + " 'slope_threshold': 0.0032531105411456656},\n", + " 'M30': {'trend': 'uptrend',\n", + " 'slope': 1.0648326715825298,\n", + " 'atr': 6.73500000000003,\n", + " 'slope_threshold': 0.0022704351807892403},\n", + " 'M15': {'trend': 'uptrend',\n", + " 'slope': 0.3136986803519024,\n", + " 'atr': 4.114285714285676,\n", + " 'slope_threshold': 0.0013869664483344836},\n", + " 'M5': {'trend': 'downtrend',\n", + " 'slope': -0.909999999999854,\n", + " 'atr': nan,\n", + " 'slope_threshold': nan},\n", + " 'top_down_trend': 'uptrend',\n", + " 'setup_ready': True,\n", + " 'entry_signal': 0}" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_top_down_signal(symbol)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'trend': 'uptrend',\n", + " 'slope': 0.8855957903085263,\n", + " 'atr': 19.30285714285713,\n", + " 'slope_threshold': 0.006484504599909453}" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_trend()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "def get_trend_fast(period):\n", + " global trend_dict, periods_dict, symbol\n", + "\n", + " df2 = get_rates(period).iloc[-200:]\n", + " df2[\"close_smooth\"] = savgol_filter(df2.close, 15, 5) # kleinere Glättung\n", + "\n", + " atr = df2.atr.iloc[-1]\n", + "\n", + " # Weniger strenge Peak-Erkennung\n", + " peaks_idx, _ = find_peaks(df2.close_smooth, distance=1, width=2, prominence=atr*0.5) #evtl kleiner 0.5\n", + " troughs_idx, _ = find_peaks(-1*df2.close_smooth, distance=1, width=2, prominence=atr*0.5)\n", + "\n", + " # Trend über Peaks/Troughs\n", + " if len(peaks_idx) > 0 and len(troughs_idx) > 0:\n", + " if peaks_idx[-1] > troughs_idx[-1]:\n", + " trend = \"downtrend\"\n", + " else:\n", + " trend = \"uptrend\"\n", + " else:\n", + " # Falls keine klaren Peaks gefunden wurden → Slope nutzen\n", + " slope = df2.close_smooth.diff().iloc[-5:].mean()\n", + " trend = \"downtrend\" if slope < 0 else \"uptrend\"\n", + "\n", + " trend_dict[period] = trend\n", + " return trend\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'uptrend'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_trend_fast('m15')" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "def set_trend():\n", + "\n", + " global pause_trading, periods_dict, trend_dict\n", + "\n", + " for k,v in trend_dict.items():\n", + " get_trend_fast(k) \n", + " print(k)\n", + " \n", + " for k,v in reversed(trend_dict.items()):\n", + "\n", + " if v == 'uptrend':\n", + " print(k,v)\n", + " periods_dict[symbol] = [k]\n", + " pause_trading = 0\n", + " print(f\"Pause Trading: {pause_trading}\")\n", + " break\n", + " elif v == 'downtrend':\n", + " periods_dict[symbol] = [k] #['m15']\n", + " pause_trading = 1\n", + " print(f\"Pause Trading: {pause_trading}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m15\n" + ] + }, + { + "ename": "KeyError", + "evalue": "'top_down'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[34], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m set_trend()\n", + "Cell \u001b[1;32mIn[33], line 6\u001b[0m, in \u001b[0;36mset_trend\u001b[1;34m()\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mglobal\u001b[39;00m pause_trading, periods_dict, trend_dict\n\u001b[0;32m 5\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k,v \u001b[38;5;129;01min\u001b[39;00m trend_dict\u001b[38;5;241m.\u001b[39mitems():\n\u001b[1;32m----> 6\u001b[0m get_trend_fast(k) \n\u001b[0;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(k)\n\u001b[0;32m 9\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k,v \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mreversed\u001b[39m(trend_dict\u001b[38;5;241m.\u001b[39mitems()):\n", + "Cell \u001b[1;32mIn[31], line 4\u001b[0m, in \u001b[0;36mget_trend_fast\u001b[1;34m(period)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_trend_fast\u001b[39m(period):\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mglobal\u001b[39;00m trend_dict, periods_dict, symbol\n\u001b[1;32m----> 4\u001b[0m df2 \u001b[38;5;241m=\u001b[39m get_rates(period)\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m200\u001b[39m:]\n\u001b[0;32m 5\u001b[0m df2[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mclose_smooth\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m savgol_filter(df2\u001b[38;5;241m.\u001b[39mclose, \u001b[38;5;241m15\u001b[39m, \u001b[38;5;241m5\u001b[39m) \u001b[38;5;66;03m# kleinere Glättung\u001b[39;00m\n\u001b[0;32m 7\u001b[0m atr \u001b[38;5;241m=\u001b[39m df2\u001b[38;5;241m.\u001b[39matr\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\n", + "Cell \u001b[1;32mIn[24], line 5\u001b[0m, in \u001b[0;36mget_rates\u001b[1;34m(periode, bars)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_rates\u001b[39m(periode, bars\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m):\n\u001b[0;32m 2\u001b[0m \u001b[38;5;66;03m#global symbol\u001b[39;00m\n\u001b[0;32m 3\u001b[0m \n\u001b[0;32m 4\u001b[0m \u001b[38;5;66;03m# OHLC abrufen\u001b[39;00m\n\u001b[1;32m----> 5\u001b[0m ohlc \u001b[38;5;241m=\u001b[39m mt\u001b[38;5;241m.\u001b[39mcopy_rates_from_pos(symbol, timeframes_dict[periode], \u001b[38;5;241m0\u001b[39m, bars)\n\u001b[0;32m 6\u001b[0m df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(ohlc)\n\u001b[0;32m 7\u001b[0m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtime\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mto_datetime(df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtime\u001b[39m\u001b[38;5;124m'\u001b[39m], unit\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[1;31mKeyError\u001b[0m: 'top_down'" + ] + } + ], + "source": [ + "set_trend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Set Trend manually" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0,\n", + " {'m15': 'uptrend',\n", + " 'top_down': {'D1': {'trend': 'uptrend',\n", + " 'slope': 4.621913228515892,\n", + " 'atr': 39.36499999999988,\n", + " 'slope_threshold': 0.013270331238569827},\n", + " 'H4': {'trend': 'uptrend',\n", + " 'slope': 0.8813408347377812,\n", + " 'atr': 20.499285714285698,\n", + " 'slope_threshold': 0.006910512170269389},\n", + " 'H1': {'trend': 'uptrend',\n", + " 'slope': 1.8054590176423853,\n", + " 'atr': 9.649999999999993,\n", + " 'slope_threshold': 0.0032531105411456656},\n", + " 'M30': {'trend': 'uptrend',\n", + " 'slope': 1.0648326715825298,\n", + " 'atr': 6.73500000000003,\n", + " 'slope_threshold': 0.0022704351807892403},\n", + " 'M15': {'trend': 'uptrend',\n", + " 'slope': 0.3136986803519024,\n", + " 'atr': 4.114285714285676,\n", + " 'slope_threshold': 0.0013869664483344836},\n", + " 'M5': {'trend': 'downtrend',\n", + " 'slope': -0.909999999999854,\n", + " 'atr': nan,\n", + " 'slope_threshold': nan},\n", + " 'top_down_trend': 'uptrend',\n", + " 'setup_ready': True,\n", + " 'entry_signal': 0},\n", + " 'm5': {'standard': 'downtrend', 'fast': 'downtrend', 'signal': -1}},\n", + " {'BTCUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'ETHUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XAUUSD': ['m15'],\n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'EURNZD': ['m5', 'm2', 'm1']},\n", + " 'XAUUSD')" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Kein Top-Down-Setup vorhanden. Kein Trade.\n" + ] + } + ], + "source": [ + "pause_trading, trend_dict, periods_dict, symbols[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m15\n" + ] + }, + { + "ename": "KeyError", + "evalue": "'top_down'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[36], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m set_trend()\n", + "Cell \u001b[1;32mIn[33], line 6\u001b[0m, in \u001b[0;36mset_trend\u001b[1;34m()\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mglobal\u001b[39;00m pause_trading, periods_dict, trend_dict\n\u001b[0;32m 5\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k,v \u001b[38;5;129;01min\u001b[39;00m trend_dict\u001b[38;5;241m.\u001b[39mitems():\n\u001b[1;32m----> 6\u001b[0m get_trend_fast(k) \n\u001b[0;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(k)\n\u001b[0;32m 9\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k,v \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mreversed\u001b[39m(trend_dict\u001b[38;5;241m.\u001b[39mitems()):\n", + "Cell \u001b[1;32mIn[31], line 4\u001b[0m, in \u001b[0;36mget_trend_fast\u001b[1;34m(period)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_trend_fast\u001b[39m(period):\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mglobal\u001b[39;00m trend_dict, periods_dict, symbol\n\u001b[1;32m----> 4\u001b[0m df2 \u001b[38;5;241m=\u001b[39m get_rates(period)\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m200\u001b[39m:]\n\u001b[0;32m 5\u001b[0m df2[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mclose_smooth\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m savgol_filter(df2\u001b[38;5;241m.\u001b[39mclose, \u001b[38;5;241m15\u001b[39m, \u001b[38;5;241m5\u001b[39m) \u001b[38;5;66;03m# kleinere Glättung\u001b[39;00m\n\u001b[0;32m 7\u001b[0m atr \u001b[38;5;241m=\u001b[39m df2\u001b[38;5;241m.\u001b[39matr\u001b[38;5;241m.\u001b[39miloc[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\n", + "Cell \u001b[1;32mIn[24], line 5\u001b[0m, in \u001b[0;36mget_rates\u001b[1;34m(periode, bars)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_rates\u001b[39m(periode, bars\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m):\n\u001b[0;32m 2\u001b[0m \u001b[38;5;66;03m#global symbol\u001b[39;00m\n\u001b[0;32m 3\u001b[0m \n\u001b[0;32m 4\u001b[0m \u001b[38;5;66;03m# OHLC abrufen\u001b[39;00m\n\u001b[1;32m----> 5\u001b[0m ohlc \u001b[38;5;241m=\u001b[39m mt\u001b[38;5;241m.\u001b[39mcopy_rates_from_pos(symbol, timeframes_dict[periode], \u001b[38;5;241m0\u001b[39m, bars)\n\u001b[0;32m 6\u001b[0m df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(ohlc)\n\u001b[0;32m 7\u001b[0m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtime\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mto_datetime(df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtime\u001b[39m\u001b[38;5;124m'\u001b[39m], unit\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[1;31mKeyError\u001b[0m: 'top_down'" + ] + } + ], + "source": [ + "set_trend()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'uptrend'" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trend_dict[periods_dict[symbol][0]]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(['m15'], 0)" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "periods_dict[symbol], pause_trading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generate signals" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "def get_mt5_data(symbol=symbol, timeframe=mt.TIMEFRAME_M15, n_bars=500):\n", + " rates = mt.copy_rates_from_pos(symbol, timeframe, 0, n_bars)\n", + " df = pd.DataFrame(rates)\n", + " df[\"time\"] = pd.to_datetime(df[\"time\"], unit=\"s\")\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "def get_m5_trade_signal(symbol, atr_mult=1.5):\n", + " global trend_dict, periods_dict\n", + "\n", + " # Hole die letzten M5-Daten\n", + " df = get_rates('m5').iloc[-200:]\n", + "\n", + " # Smoothen\n", + " df[\"close_smooth_std\"] = savgol_filter(df.close, 25, 5)\n", + " df[\"close_smooth_fast\"] = savgol_filter(df.close, 15, 5)\n", + "\n", + " atr = df.atr.iloc[-1]\n", + "\n", + " # --- Standard-Trend ---\n", + " peaks_std, _ = find_peaks(df.close_smooth_std, distance=1, width=2, prominence=atr)\n", + " troughs_std, _ = find_peaks(-df.close_smooth_std, distance=1, width=2, prominence=atr)\n", + "\n", + " if len(peaks_std) > 0 and len(troughs_std) > 0:\n", + " if peaks_std[-1] > troughs_std[-1]:\n", + " trend_standard = \"downtrend\"\n", + " else:\n", + " trend_standard = \"uptrend\"\n", + " else:\n", + " trend_standard = \"neutral\"\n", + "\n", + " # --- Fast-Trend ---\n", + " peaks_fast, _ = find_peaks(df.close_smooth_fast, distance=1, width=2, prominence=atr*0.5)\n", + " troughs_fast, _ = find_peaks(-df.close_smooth_fast, distance=1, width=2, prominence=atr*0.5)\n", + "\n", + " if len(peaks_fast) > 0 and len(troughs_fast) > 0:\n", + " if peaks_fast[-1] > troughs_fast[-1]:\n", + " trend_fast = \"downtrend\"\n", + " else:\n", + " trend_fast = \"uptrend\"\n", + " else:\n", + " slope = df.close_smooth_fast.diff().iloc[-5:].mean()\n", + " trend_fast = \"downtrend\" if slope < 0 else \"uptrend\"\n", + "\n", + " # --- Kombiniertes Signal ---\n", + " signal = 0 # 0 = neutral, 1 = long, -1 = short\n", + " stop_loss = None\n", + "\n", + " if trend_standard == \"uptrend\" and trend_fast == \"uptrend\":\n", + " signal = 1\n", + " stop_loss = df.close.iloc[-1] - atr_mult * atr\n", + " elif trend_standard == \"downtrend\" and trend_fast == \"downtrend\":\n", + " signal = -1\n", + " stop_loss = df.close.iloc[-1] + atr_mult * atr\n", + "\n", + " # Speichern\n", + " trend_dict['m5'] = {\"standard\": trend_standard, \"fast\": trend_fast, \"signal\": signal}\n", + "\n", + " return {\n", + " \"signal\": signal,\n", + " \"price\": df.close.iloc[-1],\n", + " \"stop_loss\": stop_loss,\n", + " \"trends\": trend_dict['m15']\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_signal(df = get_mt5_data(symbol=symbol, timeframe=timeframes_dict['m15']), confirm_window=3):\n", + " \"\"\"\n", + " Berechnet drei Signalarten:\n", + " - fast_signal: schnelle, aggressive Variante\n", + " - standard_signal: konservative Basisstrategie\n", + " - optimized_signal: zusätzliche Filter (ATR, ADX, strengerer RSI)\n", + " \"\"\"\n", + "\n", + " # Indikatoren\n", + " df[\"ema21\"] = df[\"close\"].ewm(span=3).mean()\n", + " df[\"ema50\"] = df[\"close\"].ewm(span=9).mean()\n", + " df[\"rsi9\"] = ta.rsi(df[\"close\"], length=9)\n", + " df[\"rsi14\"] = ta.rsi(df[\"close\"], length=14)\n", + " df[\"trend\"] = savgol_filter(df[\"close\"], 25, 3)\n", + "\n", + " # Zusätzliche Filterindikatoren\n", + " df[\"atr\"] = ta.atr(df[\"high\"], df[\"low\"], df[\"close\"], length=14)\n", + " df[\"adx\"] = ta.adx(df[\"high\"], df[\"low\"], df[\"close\"], length=14)[\"ADX_14\"]\n", + "\n", + " # Spalten für Signale\n", + " df[\"fast_signal\"] = 0\n", + " df[\"standard_signal\"] = 0\n", + " df[\"optimized_signal\"] = 0\n", + "\n", + " for i in range(1, len(df)):\n", + " # -----------------------\n", + " # FAST SIGNAL (früh/aggressiv)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"rsi9\"].iloc[i] > 30\n", + " ):\n", + " df.at[i, \"fast_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"rsi9\"].iloc[i] < 60\n", + " ):\n", + " df.at[i, \"fast_signal\"] = -1\n", + "\n", + " # -----------------------\n", + " # STANDARD SIGNAL (konservativ, ursprüngliche Logik)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] <= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] < 70\n", + " and df[\"rsi9\"].iloc[i] > 40\n", + " and df[\"trend\"].iloc[i] > df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"standard_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] >= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] > 40\n", + " and df[\"rsi9\"].iloc[i] < 70\n", + " and df[\"trend\"].iloc[i] < df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"standard_signal\"] = -1\n", + "\n", + " # -----------------------\n", + " # OPTIMIZED SIGNAL (mit ADX + ATR + strengerem RSI)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] <= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] < 65 # strengerer Filter\n", + " and df[\"rsi9\"].iloc[i] > 45 # Momentum klarer\n", + " and df[\"adx\"].iloc[i] > 20 # Trendstärke vorhanden\n", + " and df[\"atr\"].iloc[i] > df[\"atr\"].rolling(50).mean().iloc[i] # Volatilität über Durchschnitt\n", + " ):\n", + " df.at[i, \"optimized_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] >= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] > 35 # strengerer Filter unten\n", + " and df[\"rsi9\"].iloc[i] < 55\n", + " and df[\"adx\"].iloc[i] > 20\n", + " and df[\"atr\"].iloc[i] > df[\"atr\"].rolling(50).mean().iloc[i]\n", + " ):\n", + " df.at[i, \"optimized_signal\"] = -1\n", + "\n", + " return df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timeopenhighlowclosetick_volumespreadreal_volumeema21ema50rsi9rsi14trendatradxfast_signalstandard_signaloptimized_signal
02025-08-27 07:45:003374.933375.853373.943374.9324672003374.9300003374.930000NaNNaN3376.087631NaNNaN000
12025-08-27 08:00:003374.913376.213374.113374.7429042003374.8033333374.824444NaNNaN3375.914101NaNNaN000
22025-08-27 08:15:003374.733377.463374.213375.7723132003375.3557143375.211967NaNNaN3375.933879NaNNaN000
32025-08-27 08:30:003375.783378.813375.693377.6927452003376.6006673376.051409NaNNaN3376.121647NaNNaN000
42025-08-27 08:45:003377.683378.883375.853377.2323742003376.9254843376.402013NaNNaN3376.452085NaNNaN000
.........................................................
4952025-09-03 19:15:003565.403568.013564.183567.8338482003566.1953993562.94837671.92194069.3328493568.2193005.67787731.169524100
4962025-09-03 19:30:003567.833569.423566.973569.0134422003567.6026993564.16070173.43148570.3416903569.3603765.44731432.165951100
4972025-09-03 19:45:003569.013572.573568.593572.4335852003570.0163503565.81456177.39422173.1033863570.4686415.34250633.517576100
4982025-09-03 20:00:003572.453572.983570.243572.2238062003571.1181753567.09564976.60494272.6560043571.5395645.15661334.825121100
4992025-09-03 20:15:003572.263572.683571.433572.0610922003571.5890873568.08851975.94112072.2929903572.5686154.87756936.039270100
\n", + "

500 rows × 18 columns

\n", + "
" + ], + "text/plain": [ + " time open high low close tick_volume \\\n", + "0 2025-08-27 07:45:00 3374.93 3375.85 3373.94 3374.93 2467 \n", + "1 2025-08-27 08:00:00 3374.91 3376.21 3374.11 3374.74 2904 \n", + "2 2025-08-27 08:15:00 3374.73 3377.46 3374.21 3375.77 2313 \n", + "3 2025-08-27 08:30:00 3375.78 3378.81 3375.69 3377.69 2745 \n", + "4 2025-08-27 08:45:00 3377.68 3378.88 3375.85 3377.23 2374 \n", + ".. ... ... ... ... ... ... \n", + "495 2025-09-03 19:15:00 3565.40 3568.01 3564.18 3567.83 3848 \n", + "496 2025-09-03 19:30:00 3567.83 3569.42 3566.97 3569.01 3442 \n", + "497 2025-09-03 19:45:00 3569.01 3572.57 3568.59 3572.43 3585 \n", + "498 2025-09-03 20:00:00 3572.45 3572.98 3570.24 3572.22 3806 \n", + "499 2025-09-03 20:15:00 3572.26 3572.68 3571.43 3572.06 1092 \n", + "\n", + " spread real_volume ema21 ema50 rsi9 rsi14 \\\n", + "0 20 0 3374.930000 3374.930000 NaN NaN \n", + "1 20 0 3374.803333 3374.824444 NaN NaN \n", + "2 20 0 3375.355714 3375.211967 NaN NaN \n", + "3 20 0 3376.600667 3376.051409 NaN NaN \n", + "4 20 0 3376.925484 3376.402013 NaN NaN \n", + ".. ... ... ... ... ... ... \n", + "495 20 0 3566.195399 3562.948376 71.921940 69.332849 \n", + "496 20 0 3567.602699 3564.160701 73.431485 70.341690 \n", + "497 20 0 3570.016350 3565.814561 77.394221 73.103386 \n", + "498 20 0 3571.118175 3567.095649 76.604942 72.656004 \n", + "499 20 0 3571.589087 3568.088519 75.941120 72.292990 \n", + "\n", + " trend atr adx fast_signal standard_signal \\\n", + "0 3376.087631 NaN NaN 0 0 \n", + "1 3375.914101 NaN NaN 0 0 \n", + "2 3375.933879 NaN NaN 0 0 \n", + "3 3376.121647 NaN NaN 0 0 \n", + "4 3376.452085 NaN NaN 0 0 \n", + ".. ... ... ... ... ... \n", + "495 3568.219300 5.677877 31.169524 1 0 \n", + "496 3569.360376 5.447314 32.165951 1 0 \n", + "497 3570.468641 5.342506 33.517576 1 0 \n", + "498 3571.539564 5.156613 34.825121 1 0 \n", + "499 3572.568615 4.877569 36.039270 1 0 \n", + "\n", + " optimized_signal \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "495 0 \n", + "496 0 \n", + "497 0 \n", + "498 0 \n", + "499 0 \n", + "\n", + "[500 rows x 18 columns]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_signal()" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Trailing +TP for BUY XAUUSD: 3572.2200000000003 CP: 3572.06\n" + ] + } + ], + "source": [ + "pos = mt.positions_total()\n", + "\n", + "if pos > 0:\n", + " open_positions = mt.positions_get() \n", + " trail_factor = 0.5\n", + " entry_price = open_positions[0].price_open\n", + " tp_current = open_positions[0].tp\n", + " current_price = open_positions[0].price_current\n", + " profit = open_positions[0].profit\n", + "\n", + " profit = current_price - entry_price\n", + " if profit > 0:\n", + " new_tp = current_price - entry_price * trail_factor\n", + " \n", + " if profit < 0:\n", + " new_tp = current_price - profit * trail_factor \n", + "\n", + " if new_tp > current_price:\n", + " #update tp from open pos\n", + " new_tp\n", + " print(f\"Trailing +TP for BUY {symbol}: {new_tp} CP: {current_price}\")\n", + " if new_tp < current_price:\n", + " #update tp from open pos\n", + " new_tp\n", + " print(f\"Trailing -TP for BUY {symbol}: {new_tp} CP: {current_price}\")\n", + "\n", + "#open_positions\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Update TP-SL on open positions" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "def update_trailing_sl_tp(pos, atr, rrr=2.0, atr_mult=1.5, max_retries=2):\n", + " \"\"\"\n", + " Aktualisiert SL und TP für offene Positionen:\n", + " - ATR-basiertes Trailing\n", + " - Gewinn-stufenweises Nachziehen\n", + " - Dynamische Anpassung mit Validierung\n", + " - Fallback-Mechanismus bei RETCODE 1016\n", + " \"\"\"\n", + "\n", + " symbol = pos.symbol\n", + " info = mt.symbol_info(symbol)\n", + " digits = info.digits\n", + " point = info.point\n", + " stops_level = info.trade_stops_level * point # Mindestabstand vom Broker\n", + "\n", + " entry_price = pos.price_open\n", + " current_tick = mt.symbol_info_tick(symbol)\n", + " bid, ask = current_tick.bid, current_tick.ask\n", + " current_price = bid if pos.type == 0 else ask\n", + " pos_type = pos.type # 0 = BUY, 1 = SELL\n", + "\n", + " # Gewinn in ATR berechnen\n", + " if pos_type == 0: # LONG\n", + " profit_atr = (current_price - entry_price) / atr\n", + " base_sl = current_price - atr_mult * atr\n", + " new_sl = max(pos.sl or 0, base_sl)\n", + "\n", + " if profit_atr > 2:\n", + " new_sl = max(new_sl, entry_price + 1.5 * atr)\n", + " elif profit_atr > 1:\n", + " new_sl = max(new_sl, entry_price + 1.0 * atr)\n", + " elif profit_atr > 0.5:\n", + " new_sl = max(new_sl, entry_price + 0.5 * atr)\n", + "\n", + " new_tp = entry_price + (entry_price - new_sl) * rrr\n", + "\n", + " # Validierung BUY\n", + " if new_sl >= bid - stops_level:\n", + " new_sl = bid - stops_level\n", + " if new_tp <= ask + stops_level:\n", + " new_tp = ask + stops_level\n", + "\n", + " else: # SHORT\n", + " profit_atr = (entry_price - current_price) / atr\n", + " base_sl = current_price + atr_mult * atr\n", + " new_sl = min(pos.sl or 999999, base_sl)\n", + "\n", + " if profit_atr > 2:\n", + " new_sl = min(new_sl, entry_price - 1.5 * atr)\n", + " elif profit_atr > 1:\n", + " new_sl = min(new_sl, entry_price - 1.0 * atr)\n", + " elif profit_atr > 0.5:\n", + " new_sl = min(new_sl, entry_price - 0.5 * atr)\n", + "\n", + " new_tp = entry_price - (new_sl - entry_price) * rrr\n", + "\n", + " # Validierung SELL\n", + " if new_sl <= ask + stops_level:\n", + " new_sl = ask + stops_level\n", + " if new_tp >= bid - stops_level:\n", + " new_tp = bid - stops_level\n", + "\n", + " # Runden auf gültige Stellen\n", + " new_sl = round(new_sl, digits)\n", + " new_tp = round(new_tp, digits)\n", + "\n", + " # --- Nur updaten, wenn sich Werte geändert haben ---\n", + " if (pos.sl is None or abs(new_sl - pos.sl) > point) or \\\n", + " (pos.tp is None or abs(new_tp - pos.tp) > point):\n", + "\n", + " for attempt in range(max_retries):\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_SLTP,\n", + " \"symbol\": symbol,\n", + " \"sl\": new_sl,\n", + " \"tp\": new_tp,\n", + " \"position\": pos.ticket\n", + " }\n", + " result = mt.order_send(request)\n", + "\n", + " if result.retcode == mt.TRADE_RETCODE_DONE:\n", + " print(f\"🔄 Updated {symbol} | SL: {new_sl:.5f} | TP: {new_tp:.5f}\")\n", + " break\n", + " elif result.retcode == mt.TRADE_RETCODE_INVALID_STOPS:\n", + " # Fallback: Stops korrigieren\n", + " print(f\"⚠️ RETCODE 1016 (Invalid stops) – Versuch {attempt+1}/{max_retries}\")\n", + " adjust = 2 * stops_level # mehr Abstand\n", + " if pos_type == 0: # BUY\n", + " new_sl = bid - adjust\n", + " new_tp = ask + adjust\n", + " else: # SELL\n", + " new_sl = ask + adjust\n", + " new_tp = bid - adjust\n", + "\n", + " new_sl = round(new_sl, digits)\n", + " new_tp = round(new_tp, digits)\n", + " continue # retry\n", + " else:\n", + " print(f\"❌ SL/TP Update Fehler: {result.retcode} ({result.comment})\")\n", + " break\n", + "\n", + " return {\"new_sl\": new_sl, \"new_tp\": new_tp, \"profit_atr\": profit_atr}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "def manual_update_trailing_sl_tp(atr_mult=1.5, slope_factor=1.5):\n", + " # --- Hole die letzten M5-Daten ---\n", + " df = get_rates('m5').iloc[-200:]\n", + "\n", + " # --- ATR Berechnung ---\n", + " df[\"hl\"] = df[\"high\"] - df[\"low\"]\n", + " df[\"hc\"] = (df[\"high\"] - df[\"close\"].shift()).abs()\n", + " df[\"lc\"] = (df[\"low\"] - df[\"close\"].shift()).abs()\n", + " df[\"tr\"] = df[[\"hl\",\"hc\",\"lc\"]].max(axis=1)\n", + " df[\"atr\"] = df[\"tr\"].rolling(14).mean()\n", + " atr = df[\"atr\"].iloc[-1]\n", + "\n", + " current_price = df[\"close\"].iloc[-1]\n", + "\n", + " # --- Trendrichtung per Linear Regression ---\n", + " def linreg_slope(series):\n", + " X = np.arange(len(series)).reshape(-1, 1)\n", + " y = series.values.reshape(-1, 1)\n", + " model = LinearRegression().fit(X, y)\n", + " return model.coef_[0][0]\n", + "\n", + " slope_long = linreg_slope(df[\"close\"].iloc[-50:]) # 50 Balken (~4h)\n", + " slope_short = linreg_slope(df[\"close\"].iloc[-15:]) # 15 Balken (~1h)\n", + "\n", + " # --- Dynamischer Seitwärtsfilter ---\n", + " slope_threshold = slope_factor * atr / df[\"close\"].iloc[-1]\n", + "\n", + " # --- Dynamische RRR-Berechnung ---\n", + " atr_norm = atr / current_price # relative Volatilität\n", + " slope_strength = abs(slope_short) # Trendstärke aus Regression\n", + "\n", + " rrr_base = 1.2\n", + " rrr_from_vol = atr_norm * 1500 # skaliert ATR-Einfluss\n", + " rrr_from_slope = slope_strength / slope_threshold # Slope-Einfluss\n", + "\n", + " rrr = rrr_base + rrr_from_vol + rrr_from_slope\n", + " rrr = max(1.2, min(rrr, 3.0)) # Begrenzung\n", + "\n", + "\n", + " open_positions = mt.positions_get(symbol=symbol)\n", + " for pos in open_positions:\n", + " atr_value = df[\"atr\"].iloc[-1]\n", + " update_trailing_sl_tp(pos, atr=atr_value, rrr=rrr, atr_mult=atr_mult)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🔄 Updated XAUUSD | SL: 3569.71000 | TP: 3580.40000\n" + ] + } + ], + "source": [ + "manual_update_trailing_sl_tp()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get M5 Trade Signals" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "def get_m5_trade_signals(symbol=symbol, atr_mult=1.5, base_rrr=2.0, atr_min=0.0005, slope_factor=1.5, execute=False):\n", + " \"\"\"\n", + " Analyse von M5-Signalen mit ATR/Trend/Seitwärtsfilter\n", + " - execute=False -> nur Analyse\n", + " - execute=True -> führt Orders aus\n", + " \"\"\"\n", + "\n", + " global trend_dict, volume_dict\n", + "\n", + " df = get_rates('m5').iloc[-200:]\n", + "\n", + " # --- ATR ---\n", + " df[\"hl\"] = df[\"high\"] - df[\"low\"]\n", + " df[\"hc\"] = (df[\"high\"] - df[\"close\"].shift()).abs()\n", + " df[\"lc\"] = (df[\"low\"] - df[\"close\"].shift()).abs()\n", + " df[\"tr\"] = df[[\"hl\",\"hc\",\"lc\"]].max(axis=1)\n", + " df[\"atr\"] = df[\"tr\"].rolling(14).mean()\n", + " atr = df[\"atr\"].iloc[-1]\n", + "\n", + " if atr < atr_min:\n", + " return {\"signal\": 0, \"reason\": \"ATR too low → sideways\"}\n", + "\n", + " # --- Trend ---\n", + " def linreg_slope(series):\n", + " X = np.arange(len(series)).reshape(-1, 1)\n", + " y = series.values.reshape(-1, 1)\n", + " model = LinearRegression().fit(X, y)\n", + " return model.coef_[0][0]\n", + "\n", + " slope_long = linreg_slope(df[\"close\"].iloc[-50:])\n", + " slope_short = linreg_slope(df[\"close\"].iloc[-15:])\n", + " slope_threshold = slope_factor * atr / df[\"close\"].iloc[-1]\n", + "\n", + " if abs(slope_long) < slope_threshold and abs(slope_short) < slope_threshold:\n", + " return {\"signal\": 0, \"reason\": \"Trend flat → sideways\"}\n", + "\n", + " trend_standard = \"uptrend\" if slope_long > 0 else \"downtrend\"\n", + " trend_fast = \"uptrend\" if slope_short > 0 else \"downtrend\"\n", + "\n", + " current_price = df[\"close\"].iloc[-1]\n", + "\n", + " # --- RRR ---\n", + " atr_norm = atr / current_price\n", + " slope_strength = abs(slope_short)\n", + " rrr_base = 1.2\n", + " rrr_from_vol = atr_norm * 1500\n", + " rrr_from_slope = slope_strength / slope_threshold\n", + " rrr = max(1.2, min(rrr_base + rrr_from_vol + rrr_from_slope, 3.0))\n", + "\n", + " # --- Signal ---\n", + " signal, stop_loss, takeprofit = 0, None, None\n", + " if trend_standard == \"uptrend\" and trend_fast == \"uptrend\":\n", + " signal = 1\n", + " stop_loss = current_price - atr_mult * atr\n", + " takeprofit = current_price + atr_mult * atr * rrr\n", + "\n", + " if execute:\n", + " print(f\"BUY {symbol} @ {current_price} | TP: {takeprofit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"buy\", stoploss=stop_loss, take_profit=takeprofit)\n", + "\n", + " elif trend_standard == \"downtrend\" and trend_fast == \"downtrend\":\n", + " signal = -1\n", + " stop_loss = current_price + atr_mult * atr\n", + " takeprofit = current_price - atr_mult * atr * rrr\n", + "\n", + " if execute:\n", + " print(f\"SELL {symbol} @ {current_price} | TP: {takeprofit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"sell\", stoploss=stop_loss, take_profit=takeprofit)\n", + "\n", + " # --- speichern ---\n", + " trend_dict['m5'] = {\"standard\": trend_standard, \"fast\": trend_fast, \"signal\": signal}\n", + "\n", + " return {\n", + " \"signal\": signal,\n", + " \"price\": current_price,\n", + " \"stop_loss\": stop_loss,\n", + " \"take_profit\": takeprofit,\n", + " \"Risk Reward\": rrr,\n", + " \"trends\": trend_dict['m5'],\n", + " \"atr\": atr,\n", + " \"slope_long\": slope_long,\n", + " \"slope_short\": slope_short\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "def execute_m5_trade(symbol=symbol, atr_mult=1.5, base_rrr=2.0):\n", + " \"\"\"\n", + " Führt einen Trade auf M5 nur aus, wenn das Top-Down-Setup ein positives Signal liefert.\n", + " Nutzt adaptive ATR, dynamisches RRR und SL/TP.\n", + " \"\"\"\n", + "\n", + " global trend_dict, volume_dict, pause_trading\n", + "\n", + " # --- Top-Down-Signal prüfen ---\n", + " top_down = get_top_down_signal(symbol)\n", + "\n", + " if pause_trading == 1:\n", + " print(\"⚠️ Trading pausiert. Keine Trades ausgeführt.\")\n", + " return None\n", + "\n", + " if not top_down[\"setup_ready\"] or top_down[\"entry_signal\"] == 0:\n", + " print(\"Kein Top-Down-Setup vorhanden. Kein Trade.\")\n", + " return None\n", + "\n", + " # --- M5-Signal berechnen (nur Signal, keine automatische Order) ---\n", + " m5_signal_info = get_m5_trade_signals(symbol=symbol, atr_mult=atr_mult, base_rrr=base_rrr)\n", + "\n", + " if m5_signal_info[\"signal\"] == 0:\n", + " print(\"M5 Signal neutral. Kein Trade.\")\n", + " return None\n", + "\n", + " # --- Trade ausführen ---\n", + " current_price = m5_signal_info[\"price\"]\n", + " stop_loss = m5_signal_info[\"stop_loss\"]\n", + " take_profit = m5_signal_info[\"take_profit\"]\n", + "\n", + " if m5_signal_info[\"signal\"] == 1:\n", + " # Long\n", + " print(f\"✅ BUY {symbol} @ {current_price} | TP: {take_profit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"buy\", stoploss=stop_loss, take_profit=take_profit)\n", + " elif m5_signal_info[\"signal\"] == -1:\n", + " # Short\n", + " print(f\"✅ SELL {symbol} @ {current_price} | TP: {take_profit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"sell\", stoploss=stop_loss, take_profit=take_profit)\n", + "\n", + " # --- Offene Trades aktualisieren (Trailing SL/TP) ---\n", + " open_positions = mt.positions_get(symbol=symbol)\n", + " for pos in open_positions:\n", + " update_trailing_sl_tp(pos, atr=m5_signal_info[\"atr\"], rrr=m5_signal_info[\"Risk Reward\"], atr_mult=atr_mult)\n", + "\n", + " return {\n", + " \"top_down\": top_down,\n", + " \"m5_signal\": m5_signal_info\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Kein Top-Down-Setup vorhanden. Kein Trade.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ BUY XAUUSD @ 3571.06 | TP: 3578.2085714285713 | SL: 3568.677142857143\n", + "✅ BUY XAUUSD @ 3571.81 | TP: 3579.604642857143 | SL: 3569.2117857142857\n", + "🔄 Updated XAUUSD | SL: 3570.03000 | TP: 3579.44000\n", + "🔄 Updated XAUUSD | SL: 3570.58000 | TP: 3577.77000\n", + "🔄 Updated XAUUSD | SL: 3573.16000 | TP: 3573.77000\n", + "✅ BUY XAUUSD @ 3573.65 | TP: 3581.7596428571433 | SL: 3570.946785714286\n", + "🔄 Updated XAUUSD | SL: 3570.95000 | TP: 3582.31000\n", + "🔄 Updated XAUUSD | SL: 3571.07000 | TP: 3581.95000\n", + "✅ BUY XAUUSD @ 3573.67 | TP: 3581.6832142857143 | SL: 3570.9989285714287\n", + "🔄 Updated XAUUSD | SL: 3571.77000 | TP: 3579.86000\n", + "🔄 Updated XAUUSD | SL: 3571.77000 | TP: 3579.85000\n", + "✅ BUY XAUUSD @ 3574.21 | TP: 3582.0914285714284 | SL: 3571.5828571428574\n", + "🔄 Updated XAUUSD | SL: 3574.66000 | TP: 3575.40000\n", + "🔄 Updated XAUUSD | SL: 3574.67000 | TP: 3575.60000\n", + "🔄 Updated XAUUSD | SL: 3574.67000 | TP: 3575.39000\n", + "🔄 Updated XAUUSD | SL: 3574.67000 | TP: 3575.63000\n", + "🔄 Updated XAUUSD | SL: 3574.67000 | TP: 3575.68000\n", + "✅ BUY XAUUSD @ 3575.28 | TP: 3582.5957142857146 | SL: 3572.841428571429\n", + "✅ BUY XAUUSD @ 3575.47 | TP: 3583.2614285714285 | SL: 3572.872857142857\n", + "🔄 Updated XAUUSD | SL: 3572.88000 | TP: 3584.11000\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "✅ BUY XAUUSD @ 3575.29 | TP: 3583.4285714285716 | SL: 3572.577142857143\n", + "🔄 Updated XAUUSD | SL: 3573.59000 | TP: 3581.99000\n", + "🔄 Updated XAUUSD | SL: 3573.90000 | TP: 3581.07000\n", + "🔄 Updated XAUUSD | SL: 3573.90000 | TP: 3581.06000\n", + "🔄 Updated XAUUSD | SL: 3576.56000 | TP: 3577.79000\n", + "✅ BUY XAUUSD @ 3577.4 | TP: 3584.628928571429 | SL: 3574.990357142857\n", + "⚠️ RETCODE 1016 (Invalid stops) – Versuch 1/2\n", + "🔄 Updated XAUUSD | SL: 3577.00000 | TP: 3578.00000\n", + "✅ BUY XAUUSD @ 3578.23 | TP: 3586.0310714285715 | SL: 3575.6296428571427\n", + "🔄 Updated XAUUSD | SL: 3575.63000 | TP: 3586.63000\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "M5 Signal neutral. Kein Trade.\n", + "✅ SELL XAUUSD @ 3563.72 | TP: 3551.165 | SL: 3567.9049999999997\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "✅ SELL XAUUSD @ 3563.47 | TP: 3551.0532142857146 | SL: 3567.6089285714284\n", + "✅ SELL XAUUSD @ 3563.92 | TP: 3552.6603571428577 | SL: 3567.673214285714\n", + "✅ SELL XAUUSD @ 3565.45 | TP: 3553.589285714286 | SL: 3569.403571428571\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "✅ SELL XAUUSD @ 3562.22 | TP: 3553.2489285714287 | SL: 3565.210357142857\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n", + "Kein Top-Down-Setup vorhanden. Kein Trade.\n" + ] + } + ], + "source": [ + "execute_m5_trade()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Job-Scheduler\n", + "\n", + "[Doku Appscheduler Cronjob](https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html#id0)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "from apscheduler.schedulers.background import BackgroundScheduler\n", + "import time\n", + "\n", + "\n", + "scheduler = BackgroundScheduler()\n", + "#scheduler.add_job(main, 'date', run_date='2025-03-07 14:29:50')\n", + "\n", + "#scheduler.add_job(decide_order, 'interval', minutes=1) #intervall\n", + "#scheduler.add_job(set_symbol, 'interval', minutes=30)\n", + "#scheduler.add_job(set_trend, 'interval', minutes=1)\n", + "\n", + "#scheduler.add_job(decide_order, 'interval', minutes=1)\n", + "#scheduler.add_job(decide_order, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*') #cron\n", + "#scheduler.add_job(get_buy_sell_signal, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*/5') #cron\n", + "#scheduler.add_job(get_m5_trade_signals, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*/5') #cron\n", + "scheduler.add_job(execute_m5_trade, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*/5') #cron\n", + "scheduler.add_job(manual_update_trailing_sl_tp, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*') #cron\n", + "\n", + "#scheduler.add_job(export_marketview, 'cron', year=\"*\", month='*', day_of_week='mon, tue, wed; thu, fri', hour='8-22', minute=00)\n", + "\n", + "#scheduler.add_job(pause_trading, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour=22, minute=00) #cron\n", + "scheduler.start()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Jobs" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[,\n", + " ]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "scheduler.get_jobs()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remove all Jobs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scheduler.remove_all_jobs()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Shutdown AppScheduler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scheduler.shutdown()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/TradingBot_V1.ipynb b/TradingBot_V1.ipynb new file mode 100644 index 0000000..99651ac --- /dev/null +++ b/TradingBot_V1.ipynb @@ -0,0 +1,2060 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Import Libaries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install ta_lib-0.6.5-cp311-cp311-win_amd64.whl" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#%pip install talib" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install ta\n", + "from ta.trend import ADXIndicator, EMAIndicator\n", + "from ta.momentum import RSIIndicator\n", + "from talib import CDLHAMMER, CDLSHOOTINGSTAR" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import mplfinance as mpf\n", + "import keyring as kr\n", + "import MetaTrader5 as mt\n", + "import requests\n", + "import re\n", + "from time import sleep\n", + "import sqlite3 as db\n", + "#import matplotlib.pyplot as plt\n", + "import pandas_ta as ta\n", + "import numpy as np\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from scipy.signal import savgol_filter\n", + "from scipy.signal import find_peaks\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Login" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# login to your Trading Account - sign up in the description\n", + "mt.initialize()\n", + " \n", + "login = 10800246\n", + "server = 'VantageInternational-Demo'\n", + "password = kr.get_password(server, str(login))\n", + "\n", + "\n", + "mt.login(login, password, server)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'trading-demo'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "project = \"trading-\" + server[-4::1]\n", + "project = project.lower()\n", + "project" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Set symbol and volume" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "pause_trading = 0\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "symbols = ['XAUUSD']\n", + "#symbols = ['BTCUSD']\n", + "\n", + "#'BTCUSD', 'ETHUSD', \n", + " #'XRPUSD', , 'EURNZD', 'EURUSD'" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "volume_dict = {\n", + " 'BTCUSD' : 0.1,\n", + " 'BTCUSD_short' : 0.1,\n", + "\n", + " 'ETHUSD' : 1.0,\n", + " 'ETHUSD_short' : 1.0,\n", + " \n", + " 'XRPUSD': 0.1,\n", + " 'XRPUSD_short': 0.1,\n", + "\n", + " 'XAUUSD': 0.1,\n", + " 'XAUUSD_short': 0.1,\n", + "\n", + " 'EURUSD': 0.1,\n", + " 'EURUSD_short': 0.1,\n", + "\n", + " 'EURNZD': 0.1,\n", + " 'EURNZD_short': 0.1,\n", + "\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "periods_dict = {\n", + " 'BTCUSD' : ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " \n", + " 'ETHUSD' : ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + "\n", + " \n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " \n", + " 'XAUUSD': [ 'm5'],\n", + "\n", + " \n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + "\n", + "\n", + " 'EURNZD': ['m5', 'm2', 'm1'],\n", + "\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def get_symbol():\n", + " global symbols, pause_trading, periods_dict\n", + " pricemovement = {}\n", + "\n", + " for s in symbols:\n", + " items = mt.symbol_info(s)\n", + " pricemovement[s] = round(items.price_change,2)\n", + " #print(s, round(items.price_change,2))\n", + "\n", + " #percentage = pricemovement[max(pricemovement, key=pricemovement.get)]\n", + " #symbol = max(pricemovement, key=pricemovement.get)\n", + " #volume = volume_dict[symbol]\n", + "\n", + " sorted_pricemovement = sorted(pricemovement.items(), key=lambda x:x[1], reverse=True)\n", + " converted_dict = dict(sorted_pricemovement)\n", + "\n", + " print(converted_dict)\n", + "\n", + " percentage = converted_dict[max(converted_dict, key=converted_dict.get)]\n", + " symbol = max(converted_dict, key=converted_dict.get)\n", + " volume = volume_dict[symbol]\n", + "\n", + "\n", + " print(symbol, percentage, volume)\n", + " # if percentage > 0: # and percentage < 0.8:\n", + " # periods_dict[symbol] = ['m15', 'm5', 'm2', 'm1']\n", + " # elif percentage > 0.8:\n", + " # periods_dict[symbol] = ['h1', 'm30', 'm15', 'm5', 'm1']\n", + "\n", + " #\n", + "\n", + " #print(periods_dict)\n", + "\n", + " # if percentage > 0 and mt.positions_total() == 0:\n", + " # pause_trading = 0 #0 no puase\n", + " # return symbol, percentage, volume, periods_dict\n", + " # elif percentage < 0.1 and mt.positions_total() == 0:\n", + " # print(\"aktuell kein neues Symbol, pause Trading\")\n", + " # pause_trading = 1 #1 pause\n", + " # return None\n", + "\n", + " return symbol, percentage, volume, periods_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 0.93}\n", + "XAUUSD 0.93 0.1\n" + ] + }, + { + "data": { + "text/plain": [ + "('XAUUSD',\n", + " 0.93,\n", + " 0.1,\n", + " {'BTCUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'ETHUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XAUUSD': ['m5'],\n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'EURNZD': ['m5', 'm2', 'm1']})" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_symbol()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "def set_symbol():\n", + " global symbol, volume, volume_dict\n", + " symb = get_symbol()\n", + " if symb != None:\n", + " symbol = symb[0]\n", + " volume = volume_dict[symb[0]]\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## set volume manuell" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 0.93}\n", + "XAUUSD 0.93 0.1\n" + ] + }, + { + "data": { + "text/plain": [ + "('XAUUSD',\n", + " 0.93,\n", + " 0.1,\n", + " {'BTCUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'ETHUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XRPUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'XAUUSD': ['m5'],\n", + " 'EURUSD': ['h1', 'm30', 'm15', 'm5', 'm1'],\n", + " 'EURNZD': ['m5', 'm2', 'm1']})" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_symbol()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'XAUUSD': 0.93}\n", + "XAUUSD 0.93 0.1\n" + ] + } + ], + "source": [ + "set_symbol()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('XAUUSD', 0.1, 0)" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "symbol, volume, pause_trading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Functions to place Orders on Market" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pos = mt.positions_get()\n", + "for i in pos:\n", + " #if i.comment == 'Retracement Bot':\n", + " # print(i.ticket)\n", + "\n", + " if bool(re.search('^BuyStop[0-9]{2}', i.comment)):\n", + " print(i.ticket)\n", + "\n", + "mt.positions_total()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "()\n" + ] + } + ], + "source": [ + "strategy_name = 'Retracement Bot'\n", + "pos = mt.positions_get()\n", + "for p in pos:\n", + " if p.comment == strategy_name:\n", + " print(p.comment)\n", + "print(pos)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Market Order Function" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "def market_order(symbol, volume, order_type, deviation=20, magic=30, stoploss=0.0, take_profit=0.0,\n", + " strategy_name='Retracement Bot'):\n", + "\n", + " global project, pause_trading\n", + "\n", + " project_id_dict = {\n", + " 'trading-demo': 'a3f3ae',\n", + " 'trading-live': '747543'\n", + " }\n", + "\n", + " order_type_dict = {\n", + " 'buy': mt.ORDER_TYPE_BUY,\n", + " 'sell': mt.ORDER_TYPE_SELL\n", + " }\n", + "\n", + " price_dict = {\n", + " 'buy': mt.symbol_info_tick(symbol).ask,\n", + " 'sell': mt.symbol_info_tick(symbol).bid\n", + " }\n", + "\n", + " buypos = []\n", + "\n", + " pos = mt.positions_get()\n", + " for p in pos:\n", + " if p.comment == strategy_name:\n", + " buypos.append('true')\n", + " \n", + " activepos = buypos.count('true')\n", + "\n", + " if order_type == 'buy' and activepos == 0 and pause_trading == 0: # and mt.positions_total() == 0:\n", + " \n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume, # FLOAT\n", + " \"type\": order_type_dict[order_type],\n", + " \"price\": price_dict[order_type],\n", + " \"sl\": stoploss, # FLOAT\n", + " \"tp\": take_profit, # FLOAT\n", + " \"deviation\": deviation, # INTERGER\n", + " \"magic\": magic, # INTERGER\n", + " \"comment\": strategy_name,\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC, # mt.ORDER_FILLING_FOK if IOC does not work\n", + " }\n", + "\n", + " requests.post('https://api.mynotifier.app', {\n", + " \"apiKey\": 'beafb52e-3cb6-477a-92ef-2f10bff50e20',\n", + " \"message\": \"Es wrude ein Handel eröffnet!\",\n", + " \"description\": \"Bitte kontrolliere die Position\",\n", + " \"type\": \"info\",#\"info\", # info, error, warning or success\n", + " \"project\": project_id_dict[project]\n", + " })\n", + "\n", + " order_result = mt.order_send(request)\n", + " #return (order_result)\n", + " \n", + " elif order_type == 'sell' and mt.positions_total() > 0:\n", + " pos = mt.positions_get()\n", + " for p in pos:\n", + " if p.comment == strategy_name:\n", + " # while schleife ?\n", + " positions = mt.positions_get()\n", + " ticket = p.ticket\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_DEAL,\n", + " \"symbol\": symbol,\n", + " \"volume\": volume, # FLOAT\n", + " \"type\": order_type_dict[order_type],\n", + " \"price\": price_dict[order_type],\n", + " \"position\": ticket,\n", + " \"sl\": stoploss, # FLOAT\n", + " \"tp\": take_profit, # FLOAT\n", + " \"deviation\": deviation, # INTERGER\n", + " \"magic\": magic, # INTERGER\n", + " \"comment\": strategy_name,\n", + " \"type_time\": mt.ORDER_TIME_GTC,\n", + " \"type_filling\": mt.ORDER_FILLING_IOC, # mt.ORDER_FILLING_FOK if IOC does not work\n", + " }\n", + "\n", + " requests.post('https://api.mynotifier.app', {\n", + " \"apiKey\": 'beafb52e-3cb6-477a-92ef-2f10bff50e20',\n", + " \"message\": \"Es wrude ein Handel geschlossen!\",\n", + " \"description\": \"Bitte prüfe die Position\",\n", + " \"type\": \"info\",#\"info\", # info, error, warning or success\n", + " \"project\": project_id_dict[project]\n", + " })\n", + "\n", + " order_result = mt.order_send(request)\n", + " #return (order_result)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trend Detection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## timefame & trend dictionary" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "debug = False" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "trend_dict = {\n", + " 'm5': '',\n", + " #'m10': '',\n", + " #'m15': '',\n", + " #'m30': '',\n", + " #'h4': '',\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "timeframes_dict = {\n", + " 'm1': mt.TIMEFRAME_M1,\n", + " 'm2': mt.TIMEFRAME_M2,\n", + " 'm3': mt.TIMEFRAME_M3,\n", + " 'm5': mt.TIMEFRAME_M5,\n", + " 'm15': mt.TIMEFRAME_M15,\n", + " 'm20': mt.TIMEFRAME_M20,\n", + " 'm30': mt.TIMEFRAME_M30,\n", + " 'h1': mt.TIMEFRAME_H1,\n", + " 'h4': mt.TIMEFRAME_H4,\n", + "}\n", + "\n", + "\n", + "# timeframes = {\n", + "# 'm1': mt.TIMEFRAME_M1,\n", + "# 'm2': mt.TIMEFRAME_M2,\n", + "# 'm3': mt.TIMEFRAME_M3,\n", + "# 'm5': mt.TIMEFRAME_M5,\n", + "# 'm15': mt.TIMEFRAME_M15,\n", + "# 'm20': mt.TIMEFRAME_M20,\n", + "# 'm30': mt.TIMEFRAME_M30,\n", + "# 'h1': mt.TIMEFRAME_H1,\n", + "# }" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'m5': ''}\n" + ] + } + ], + "source": [ + "print(trend_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "def get_rates(periode):\n", + "\n", + " global symbol\n", + "\n", + " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[periode], 0, 300)\n", + " df = pd.DataFrame(ohlc)\n", + " df['time']=pd.to_datetime(df['time'], unit='s')\n", + "\n", + " #df = df[[\"time\",\"open\",\"high\",\"low\",\"close\"]]\n", + "\n", + " df[\"open\"] = df.open.astype(float)\n", + " df[\"high\"] = df.high.astype(float)\n", + " df[\"low\"] = df.low.astype(float)\n", + " df[\"close\"] = df.close.astype(float)\n", + "\n", + " ## Take the rolling atr so the yaxis doesn't shake too much \n", + " df[\"atr\"] = ta.atr(high=df.high, low=df.low, close=df.close)\n", + " df[\"atr\"] = df.atr.rolling(window=30).mean()\n", + "\n", + "\n", + " df.set_index(\"time\", inplace = True)\n", + "\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
openhighlowclosetick_volumespreadreal_volumeatr
time
2025-08-28 22:00:003420.043420.353419.773419.851045200NaN
2025-08-28 22:05:003419.823420.013418.743418.901057200NaN
2025-08-28 22:10:003418.933419.203418.273418.621003200NaN
2025-08-28 22:15:003418.623419.813418.553419.691218200NaN
2025-08-28 22:20:003419.673420.013419.153419.17956200NaN
...........................
2025-08-29 23:35:003447.783448.553447.183448.215462001.968904
2025-08-29 23:40:003448.213449.353447.783449.174212001.961315
2025-08-29 23:45:003449.153449.183447.643447.905782001.955341
2025-08-29 23:50:003447.863448.363447.683448.224672001.947173
2025-08-29 23:55:003448.203448.913447.973448.872282001.938756
\n", + "

300 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " open high low close tick_volume spread \\\n", + "time \n", + "2025-08-28 22:00:00 3420.04 3420.35 3419.77 3419.85 1045 20 \n", + "2025-08-28 22:05:00 3419.82 3420.01 3418.74 3418.90 1057 20 \n", + "2025-08-28 22:10:00 3418.93 3419.20 3418.27 3418.62 1003 20 \n", + "2025-08-28 22:15:00 3418.62 3419.81 3418.55 3419.69 1218 20 \n", + "2025-08-28 22:20:00 3419.67 3420.01 3419.15 3419.17 956 20 \n", + "... ... ... ... ... ... ... \n", + "2025-08-29 23:35:00 3447.78 3448.55 3447.18 3448.21 546 20 \n", + "2025-08-29 23:40:00 3448.21 3449.35 3447.78 3449.17 421 20 \n", + "2025-08-29 23:45:00 3449.15 3449.18 3447.64 3447.90 578 20 \n", + "2025-08-29 23:50:00 3447.86 3448.36 3447.68 3448.22 467 20 \n", + "2025-08-29 23:55:00 3448.20 3448.91 3447.97 3448.87 228 20 \n", + "\n", + " real_volume atr \n", + "time \n", + "2025-08-28 22:00:00 0 NaN \n", + "2025-08-28 22:05:00 0 NaN \n", + "2025-08-28 22:10:00 0 NaN \n", + "2025-08-28 22:15:00 0 NaN \n", + "2025-08-28 22:20:00 0 NaN \n", + "... ... ... \n", + "2025-08-29 23:35:00 0 1.968904 \n", + "2025-08-29 23:40:00 0 1.961315 \n", + "2025-08-29 23:45:00 0 1.955341 \n", + "2025-08-29 23:50:00 0 1.947173 \n", + "2025-08-29 23:55:00 0 1.938756 \n", + "\n", + "[300 rows x 8 columns]" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_rates('m5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Wirkung |\n", + "| ------------ | ------------------------------------------- |\n", + "| `distance` | Wie **nah beieinander** Peaks liegen dürfen |\n", + "| `width` | Wie **breit/flach** ein Peak sein muss |\n", + "| `prominence` | Wie **stark auffällig** ein Peak sein muss |\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "def get_trend(period):\n", + "\n", + " global trend_dict, periods_dict, symbol, debug\n", + "\n", + " #current_periods = periods_dict[symbol][0]\n", + "\n", + " df2 = get_rates(period).iloc[-200:]\n", + "\n", + " df2[\"close_smooth\"] = savgol_filter(df2.close, 25, 5)\n", + "\n", + " fig, ax = plt.subplots()\n", + " plt.xticks(rotation=-30)\n", + " price, = ax.plot(df2.index, df2.close, c='grey', lw=2, alpha=0.5, zorder=5)\n", + " price_smooth, = ax.plot(df2.index, df2.close_smooth, c='b', lw=2, zorder=5)\n", + "\n", + " atr = df2.atr.iloc[-1] # all the first atrs are NaN\n", + "\n", + " peaks_idx, _ = find_peaks(df2.close_smooth, distance = 1, \n", + " width = 2, prominence=atr)\n", + "\n", + " troughs_idx, _ = find_peaks(-1*df2.close_smooth, distance = 1, \n", + " width = 2, prominence=atr)\n", + "\n", + " \n", + "\n", + " peaks, = ax.plot(df2.index[peaks_idx], df2.close_smooth.iloc[peaks_idx], \\\n", + " c=\"r\", linestyle='None', markersize = 10.0, marker = \"o\", zorder=10)\n", + "\n", + " troughs, = ax.plot(df2.index[troughs_idx], df2.close_smooth.iloc[troughs_idx], \\\n", + " c=\"g\", linestyle='None', markersize = 10.0, marker = \"o\", zorder=10)\n", + "\n", + "\n", + " plt.show()\n", + "\n", + " #print(peaks_idx[-1], troughs_idx[-1])\n", + "\n", + " if peaks_idx[-1] > troughs_idx[-1]:\n", + " print(\"downtrend\")\n", + "\n", + " trend_dict[period] = 'downtrend'\n", + " else:\n", + " print(\"uptrend\")\n", + "\n", + " trend_dict[period] = 'uptrend'\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "def get_trend_fast(period):\n", + " global trend_dict, periods_dict, symbol\n", + "\n", + " df2 = get_rates(period).iloc[-200:]\n", + " df2[\"close_smooth\"] = savgol_filter(df2.close, 15, 5) # kleinere Glättung\n", + "\n", + " atr = df2.atr.iloc[-1]\n", + "\n", + " # Weniger strenge Peak-Erkennung\n", + " peaks_idx, _ = find_peaks(df2.close_smooth, distance=1, width=2, prominence=atr*0.5) #evtl kleiner 0.5\n", + " troughs_idx, _ = find_peaks(-1*df2.close_smooth, distance=1, width=2, prominence=atr*0.5)\n", + "\n", + " # Trend über Peaks/Troughs\n", + " if len(peaks_idx) > 0 and len(troughs_idx) > 0:\n", + " if peaks_idx[-1] > troughs_idx[-1]:\n", + " trend = \"downtrend\"\n", + " else:\n", + " trend = \"uptrend\"\n", + " else:\n", + " # Falls keine klaren Peaks gefunden wurden → Slope nutzen\n", + " slope = df2.close_smooth.diff().iloc[-5:].mean()\n", + " trend = \"downtrend\" if slope < 0 else \"uptrend\"\n", + "\n", + " trend_dict[period] = trend\n", + " return trend\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'downtrend'" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_trend_fast('m5')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "def set_trend():\n", + "\n", + " global pause_trading, periods_dict, trend_dict\n", + "\n", + " for k,v in trend_dict.items():\n", + " get_trend_fast(k) \n", + " print(k)\n", + " \n", + " for k,v in reversed(trend_dict.items()):\n", + "\n", + " if v == 'uptrend':\n", + " print(k,v)\n", + " periods_dict[symbol] = [k]\n", + " pause_trading = 0\n", + " print(f\"Pause Trading: {pause_trading}\")\n", + " break\n", + " elif v == 'downtrend':\n", + " periods_dict[symbol] = [k] #['m15']\n", + " pause_trading = 1\n", + " print(f\"Pause Trading: {pause_trading}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m5\n", + "Pause Trading: 1\n" + ] + } + ], + "source": [ + "set_trend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Set Trend manually" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pause_trading, trend_dict, periods_dict, symbols[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m5\n", + "m5 uptrend\n", + "Pause Trading: 0\n" + ] + } + ], + "source": [ + "set_trend()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'uptrend'" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trend_dict[periods_dict[symbol][0]]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(['m5'], 0)" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "periods_dict[symbol], pause_trading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Job-Scheduler\n", + "\n", + "[Doku Appscheduler Cronjob](https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html#id0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from apscheduler.schedulers.background import BackgroundScheduler\n", + "import time\n", + "\n", + "\n", + "scheduler = BackgroundScheduler()\n", + "#scheduler.add_job(main, 'date', run_date='2025-03-07 14:29:50')\n", + "\n", + "#scheduler.add_job(decide_order, 'interval', minutes=1) #intervall\n", + "#scheduler.add_job(set_symbol, 'interval', minutes=30)\n", + "#scheduler.add_job(set_trend, 'interval', minutes=1)\n", + "\n", + "#scheduler.add_job(decide_order, 'interval', minutes=1)\n", + "#scheduler.add_job(decide_order, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*') #cron\n", + "#scheduler.add_job(get_buy_sell_signal, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*/5') #cron\n", + "scheduler.add_job(get_m5_trade_signals, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*/5') #cron\n", + "\n", + "#scheduler.add_job(export_marketview, 'cron', year=\"*\", month='*', day_of_week='mon, tue, wed; thu, fri', hour='8-22', minute=00)\n", + "\n", + "#scheduler.add_job(pause_trading, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour=22, minute=00) #cron\n", + "scheduler.start()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Jobs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scheduler.get_jobs()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remove all Jobs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scheduler.remove_all_jobs()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Shutdown AppScheduler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scheduler.shutdown()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generate signals" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "def get_mt5_data(symbol=symbol, timeframe=mt.TIMEFRAME_M5, n_bars=500):\n", + " rates = mt.copy_rates_from_pos(symbol, timeframe, 0, n_bars)\n", + " df = pd.DataFrame(rates)\n", + " df[\"time\"] = pd.to_datetime(df[\"time\"], unit=\"s\")\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "def get_m5_trade_signal(symbol, atr_mult=1.5):\n", + " global trend_dict, periods_dict\n", + "\n", + " # Hole die letzten M5-Daten\n", + " df = get_rates('m5').iloc[-200:]\n", + "\n", + " # Smoothen\n", + " df[\"close_smooth_std\"] = savgol_filter(df.close, 25, 5)\n", + " df[\"close_smooth_fast\"] = savgol_filter(df.close, 15, 5)\n", + "\n", + " atr = df.atr.iloc[-1]\n", + "\n", + " # --- Standard-Trend ---\n", + " peaks_std, _ = find_peaks(df.close_smooth_std, distance=1, width=2, prominence=atr)\n", + " troughs_std, _ = find_peaks(-df.close_smooth_std, distance=1, width=2, prominence=atr)\n", + "\n", + " if len(peaks_std) > 0 and len(troughs_std) > 0:\n", + " if peaks_std[-1] > troughs_std[-1]:\n", + " trend_standard = \"downtrend\"\n", + " else:\n", + " trend_standard = \"uptrend\"\n", + " else:\n", + " trend_standard = \"neutral\"\n", + "\n", + " # --- Fast-Trend ---\n", + " peaks_fast, _ = find_peaks(df.close_smooth_fast, distance=1, width=2, prominence=atr*0.5)\n", + " troughs_fast, _ = find_peaks(-df.close_smooth_fast, distance=1, width=2, prominence=atr*0.5)\n", + "\n", + " if len(peaks_fast) > 0 and len(troughs_fast) > 0:\n", + " if peaks_fast[-1] > troughs_fast[-1]:\n", + " trend_fast = \"downtrend\"\n", + " else:\n", + " trend_fast = \"uptrend\"\n", + " else:\n", + " slope = df.close_smooth_fast.diff().iloc[-5:].mean()\n", + " trend_fast = \"downtrend\" if slope < 0 else \"uptrend\"\n", + "\n", + " # --- Kombiniertes Signal ---\n", + " signal = 0 # 0 = neutral, 1 = long, -1 = short\n", + " stop_loss = None\n", + "\n", + " if trend_standard == \"uptrend\" and trend_fast == \"uptrend\":\n", + " signal = 1\n", + " stop_loss = df.close.iloc[-1] - atr_mult * atr\n", + " elif trend_standard == \"downtrend\" and trend_fast == \"downtrend\":\n", + " signal = -1\n", + " stop_loss = df.close.iloc[-1] + atr_mult * atr\n", + "\n", + " # Speichern\n", + " trend_dict['m5'] = {\"standard\": trend_standard, \"fast\": trend_fast, \"signal\": signal}\n", + "\n", + " return {\n", + " \"signal\": signal,\n", + " \"price\": df.close.iloc[-1],\n", + " \"stop_loss\": stop_loss,\n", + " \"trends\": trend_dict['m5']\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_signal(df = get_mt5_data(symbol=symbol, timeframe=timeframes_dict['m5']), confirm_window=3):\n", + " \"\"\"\n", + " Berechnet drei Signalarten:\n", + " - fast_signal: schnelle, aggressive Variante\n", + " - standard_signal: konservative Basisstrategie\n", + " - optimized_signal: zusätzliche Filter (ATR, ADX, strengerer RSI)\n", + " \"\"\"\n", + "\n", + " # Indikatoren\n", + " df[\"ema21\"] = df[\"close\"].ewm(span=3).mean()\n", + " df[\"ema50\"] = df[\"close\"].ewm(span=9).mean()\n", + " df[\"rsi9\"] = ta.rsi(df[\"close\"], length=9)\n", + " df[\"rsi14\"] = ta.rsi(df[\"close\"], length=14)\n", + " df[\"trend\"] = savgol_filter(df[\"close\"], 25, 3)\n", + "\n", + " # Zusätzliche Filterindikatoren\n", + " df[\"atr\"] = ta.atr(df[\"high\"], df[\"low\"], df[\"close\"], length=14)\n", + " df[\"adx\"] = ta.adx(df[\"high\"], df[\"low\"], df[\"close\"], length=14)[\"ADX_14\"]\n", + "\n", + " # Spalten für Signale\n", + " df[\"fast_signal\"] = 0\n", + " df[\"standard_signal\"] = 0\n", + " df[\"optimized_signal\"] = 0\n", + "\n", + " for i in range(1, len(df)):\n", + " # -----------------------\n", + " # FAST SIGNAL (früh/aggressiv)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"rsi9\"].iloc[i] > 30\n", + " ):\n", + " df.at[i, \"fast_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"rsi9\"].iloc[i] < 60\n", + " ):\n", + " df.at[i, \"fast_signal\"] = -1\n", + "\n", + " # -----------------------\n", + " # STANDARD SIGNAL (konservativ, ursprüngliche Logik)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] <= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] < 70\n", + " and df[\"rsi9\"].iloc[i] > 40\n", + " and df[\"trend\"].iloc[i] > df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"standard_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] >= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] > 40\n", + " and df[\"rsi9\"].iloc[i] < 70\n", + " and df[\"trend\"].iloc[i] < df[\"trend\"].iloc[i - 1]\n", + " ):\n", + " df.at[i, \"standard_signal\"] = -1\n", + "\n", + " # -----------------------\n", + " # OPTIMIZED SIGNAL (mit ADX + ATR + strengerem RSI)\n", + " # -----------------------\n", + " if (\n", + " df[\"ema21\"].iloc[i] > df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] <= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] < 65 # strengerer Filter\n", + " and df[\"rsi9\"].iloc[i] > 45 # Momentum klarer\n", + " and df[\"adx\"].iloc[i] > 20 # Trendstärke vorhanden\n", + " and df[\"atr\"].iloc[i] > df[\"atr\"].rolling(50).mean().iloc[i] # Volatilität über Durchschnitt\n", + " ):\n", + " df.at[i, \"optimized_signal\"] = 1\n", + " elif (\n", + " df[\"ema21\"].iloc[i] < df[\"ema50\"].iloc[i]\n", + " and df[\"ema21\"].iloc[i - 1] >= df[\"ema50\"].iloc[i - 1]\n", + " and df[\"rsi14\"].iloc[i] > 35 # strengerer Filter unten\n", + " and df[\"rsi9\"].iloc[i] < 55\n", + " and df[\"adx\"].iloc[i] > 20\n", + " and df[\"atr\"].iloc[i] > df[\"atr\"].rolling(50).mean().iloc[i]\n", + " ):\n", + " df.at[i, \"optimized_signal\"] = -1\n", + "\n", + " return df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timeopenhighlowclosetick_volumespreadreal_volumeema21ema50rsi9rsi14trendatradxfast_signalstandard_signaloptimized_signal
02025-08-28 05:25:003386.523386.743385.713386.647142003386.6400003386.640000NaNNaN3385.220875NaNNaN000
12025-08-28 05:30:003386.753386.983385.813385.859852003386.1133333386.201111NaNNaN3386.775285NaNNaN000
22025-08-28 05:35:003385.863387.383384.593387.1711512003386.7171433386.598197NaNNaN3388.065491NaNNaN000
32025-08-28 05:40:003387.123388.363386.823388.187982003387.4973333387.134038NaNNaN3389.112151NaNNaN000
42025-08-28 05:45:003388.163390.563387.943390.469472003389.0264523388.123436NaNNaN3389.935928NaNNaN000
.........................................................
4952025-08-29 23:40:003448.213449.353447.783449.174212003448.7432303448.45688156.59171656.4527483448.2675852.00296815.874639100
4962025-08-29 23:45:003449.153449.183447.643447.905782003448.3216153448.34550550.15067052.2093093447.9416981.96989915.547755-1-10
4972025-08-29 23:50:003447.863448.363447.683448.224672003448.2708083448.32040451.70868453.1646053447.5706851.87776415.244220-100
4982025-08-29 23:55:003448.203448.913447.973448.872282003448.5704043448.43032354.92780155.1267473447.1566511.81078015.232676100
4992025-09-01 01:00:003444.733449.273444.673445.142452003446.8552023447.77225838.40181443.7895283446.7017032.01001014.843679-1-10
\n", + "

500 rows × 18 columns

\n", + "
" + ], + "text/plain": [ + " time open high low close tick_volume \\\n", + "0 2025-08-28 05:25:00 3386.52 3386.74 3385.71 3386.64 714 \n", + "1 2025-08-28 05:30:00 3386.75 3386.98 3385.81 3385.85 985 \n", + "2 2025-08-28 05:35:00 3385.86 3387.38 3384.59 3387.17 1151 \n", + "3 2025-08-28 05:40:00 3387.12 3388.36 3386.82 3388.18 798 \n", + "4 2025-08-28 05:45:00 3388.16 3390.56 3387.94 3390.46 947 \n", + ".. ... ... ... ... ... ... \n", + "495 2025-08-29 23:40:00 3448.21 3449.35 3447.78 3449.17 421 \n", + "496 2025-08-29 23:45:00 3449.15 3449.18 3447.64 3447.90 578 \n", + "497 2025-08-29 23:50:00 3447.86 3448.36 3447.68 3448.22 467 \n", + "498 2025-08-29 23:55:00 3448.20 3448.91 3447.97 3448.87 228 \n", + "499 2025-09-01 01:00:00 3444.73 3449.27 3444.67 3445.14 245 \n", + "\n", + " spread real_volume ema21 ema50 rsi9 rsi14 \\\n", + "0 20 0 3386.640000 3386.640000 NaN NaN \n", + "1 20 0 3386.113333 3386.201111 NaN NaN \n", + "2 20 0 3386.717143 3386.598197 NaN NaN \n", + "3 20 0 3387.497333 3387.134038 NaN NaN \n", + "4 20 0 3389.026452 3388.123436 NaN NaN \n", + ".. ... ... ... ... ... ... \n", + "495 20 0 3448.743230 3448.456881 56.591716 56.452748 \n", + "496 20 0 3448.321615 3448.345505 50.150670 52.209309 \n", + "497 20 0 3448.270808 3448.320404 51.708684 53.164605 \n", + "498 20 0 3448.570404 3448.430323 54.927801 55.126747 \n", + "499 20 0 3446.855202 3447.772258 38.401814 43.789528 \n", + "\n", + " trend atr adx fast_signal standard_signal \\\n", + "0 3385.220875 NaN NaN 0 0 \n", + "1 3386.775285 NaN NaN 0 0 \n", + "2 3388.065491 NaN NaN 0 0 \n", + "3 3389.112151 NaN NaN 0 0 \n", + "4 3389.935928 NaN NaN 0 0 \n", + ".. ... ... ... ... ... \n", + "495 3448.267585 2.002968 15.874639 1 0 \n", + "496 3447.941698 1.969899 15.547755 -1 -1 \n", + "497 3447.570685 1.877764 15.244220 -1 0 \n", + "498 3447.156651 1.810780 15.232676 1 0 \n", + "499 3446.701703 2.010010 14.843679 -1 -1 \n", + "\n", + " optimized_signal \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "495 0 \n", + "496 0 \n", + "497 0 \n", + "498 0 \n", + "499 0 \n", + "\n", + "[500 rows x 18 columns]" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_signal()" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "pos = mt.positions_total()\n", + "\n", + "if pos > 0:\n", + " open_positions = mt.positions_get() \n", + " trail_factor = 0.5\n", + " entry_price = open_positions[0].price_open\n", + " tp_current = open_positions[0].tp\n", + " current_price = open_positions[0].price_current\n", + " profit = open_positions[0].profit\n", + "\n", + " profit = current_price - entry_price\n", + " if profit > 0:\n", + " new_tp = current_price - entry_price * trail_factor\n", + " \n", + " if profit < 0:\n", + " new_tp = current_price - profit * trail_factor \n", + "\n", + " if new_tp > current_price:\n", + " #update tp from open pos\n", + " new_tp\n", + " print(f\"Trailing +TP for BUY {symbol}: {new_tp} CP: {current_price}\")\n", + " if new_tp < current_price:\n", + " #update tp from open pos\n", + " new_tp\n", + " print(f\"Trailing -TP for BUY {symbol}: {new_tp} CP: {current_price}\")\n", + "\n", + "#open_positions\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Update TP-SL on open positions" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "def update_trailing_sl_tp(pos, atr, rrr=2.0, atr_mult=1.5, max_retries=2):\n", + " \"\"\"\n", + " Aktualisiert SL und TP für offene Positionen:\n", + " - ATR-basiertes Trailing\n", + " - Gewinn-stufenweises Nachziehen\n", + " - Dynamische Anpassung mit Validierung\n", + " - Fallback-Mechanismus bei RETCODE 1016\n", + " \"\"\"\n", + "\n", + " symbol = pos.symbol\n", + " info = mt.symbol_info(symbol)\n", + " digits = info.digits\n", + " point = info.point\n", + " stops_level = info.trade_stops_level * point # Mindestabstand vom Broker\n", + "\n", + " entry_price = pos.price_open\n", + " current_tick = mt.symbol_info_tick(symbol)\n", + " bid, ask = current_tick.bid, current_tick.ask\n", + " current_price = bid if pos.type == 0 else ask\n", + " pos_type = pos.type # 0 = BUY, 1 = SELL\n", + "\n", + " # Gewinn in ATR berechnen\n", + " if pos_type == 0: # LONG\n", + " profit_atr = (current_price - entry_price) / atr\n", + " base_sl = current_price - atr_mult * atr\n", + " new_sl = max(pos.sl or 0, base_sl)\n", + "\n", + " if profit_atr > 2:\n", + " new_sl = max(new_sl, entry_price + 1.5 * atr)\n", + " elif profit_atr > 1:\n", + " new_sl = max(new_sl, entry_price + 1.0 * atr)\n", + " elif profit_atr > 0.5:\n", + " new_sl = max(new_sl, entry_price + 0.5 * atr)\n", + "\n", + " new_tp = entry_price + (entry_price - new_sl) * rrr\n", + "\n", + " # Validierung BUY\n", + " if new_sl >= bid - stops_level:\n", + " new_sl = bid - stops_level\n", + " if new_tp <= ask + stops_level:\n", + " new_tp = ask + stops_level\n", + "\n", + " else: # SHORT\n", + " profit_atr = (entry_price - current_price) / atr\n", + " base_sl = current_price + atr_mult * atr\n", + " new_sl = min(pos.sl or 999999, base_sl)\n", + "\n", + " if profit_atr > 2:\n", + " new_sl = min(new_sl, entry_price - 1.5 * atr)\n", + " elif profit_atr > 1:\n", + " new_sl = min(new_sl, entry_price - 1.0 * atr)\n", + " elif profit_atr > 0.5:\n", + " new_sl = min(new_sl, entry_price - 0.5 * atr)\n", + "\n", + " new_tp = entry_price - (new_sl - entry_price) * rrr\n", + "\n", + " # Validierung SELL\n", + " if new_sl <= ask + stops_level:\n", + " new_sl = ask + stops_level\n", + " if new_tp >= bid - stops_level:\n", + " new_tp = bid - stops_level\n", + "\n", + " # Runden auf gültige Stellen\n", + " new_sl = round(new_sl, digits)\n", + " new_tp = round(new_tp, digits)\n", + "\n", + " # --- Nur updaten, wenn sich Werte geändert haben ---\n", + " if (pos.sl is None or abs(new_sl - pos.sl) > point) or \\\n", + " (pos.tp is None or abs(new_tp - pos.tp) > point):\n", + "\n", + " for attempt in range(max_retries):\n", + " request = {\n", + " \"action\": mt.TRADE_ACTION_SLTP,\n", + " \"symbol\": symbol,\n", + " \"sl\": new_sl,\n", + " \"tp\": new_tp,\n", + " \"position\": pos.ticket\n", + " }\n", + " result = mt.order_send(request)\n", + "\n", + " if result.retcode == mt.TRADE_RETCODE_DONE:\n", + " print(f\"🔄 Updated {symbol} | SL: {new_sl:.5f} | TP: {new_tp:.5f}\")\n", + " break\n", + " elif result.retcode == mt.TRADE_RETCODE_INVALID_STOPS:\n", + " # Fallback: Stops korrigieren\n", + " print(f\"⚠️ RETCODE 1016 (Invalid stops) – Versuch {attempt+1}/{max_retries}\")\n", + " adjust = 2 * stops_level # mehr Abstand\n", + " if pos_type == 0: # BUY\n", + " new_sl = bid - adjust\n", + " new_tp = ask + adjust\n", + " else: # SELL\n", + " new_sl = ask + adjust\n", + " new_tp = bid - adjust\n", + "\n", + " new_sl = round(new_sl, digits)\n", + " new_tp = round(new_tp, digits)\n", + " continue # retry\n", + " else:\n", + " print(f\"❌ SL/TP Update Fehler: {result.retcode} ({result.comment})\")\n", + " break\n", + "\n", + " return {\"new_sl\": new_sl, \"new_tp\": new_tp, \"profit_atr\": profit_atr}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get M5 Trade Signals" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_m5_trade_signals(symbol=symbol, atr_mult=1.5, base_rrr=2.0, atr_min=0.0005, slope_factor=1.5):\n", + " \"\"\"\n", + " M5 Trade Signal mit dynamischem Seitwärtsfilter + dynamischer RRR-Berechnung:\n", + " - ATR-Minimum prüft ob Markt volatil genug ist\n", + " - Linear Regression ersetzt Savitzky-Golay für Trenddetektion\n", + " - adaptive Filterung nach ATR und Trend-Slope\n", + " - dynamisches RRR (Chance-Risiko-Verhältnis) auf Basis von ATR + Slope\n", + " \"\"\"\n", + "\n", + " global trend_dict, periods_dict, pause_trading, volume_dict\n", + " set_trend()\n", + "\n", + " # if pause_trading == 1:\n", + " # pos = mt.positions_total()\n", + " # if pos > 0:\n", + " # open_positions = mt.positions_get()\n", + " # print(f\"⚠️ Trading pausiert, offene Positionen auf {symbol} werden geschlossen...\")\n", + " # for pos in open_positions:\n", + " # market_order(symbol, volume_dict[symbol], \"sell\")\n", + " # return {\"signal\": 0, \"reason\": \"Trading paused\"}\n", + "\n", + " # --- Hole die letzten M5-Daten ---\n", + " df = get_rates('m5').iloc[-200:]\n", + "\n", + " # --- ATR Berechnung ---\n", + " df[\"hl\"] = df[\"high\"] - df[\"low\"]\n", + " df[\"hc\"] = (df[\"high\"] - df[\"close\"].shift()).abs()\n", + " df[\"lc\"] = (df[\"low\"] - df[\"close\"].shift()).abs()\n", + " df[\"tr\"] = df[[\"hl\",\"hc\",\"lc\"]].max(axis=1)\n", + " df[\"atr\"] = df[\"tr\"].rolling(14).mean()\n", + " atr = df[\"atr\"].iloc[-1]\n", + "\n", + " if atr < atr_min:\n", + " return {\"signal\": 0, \"reason\": \"ATR too low → sideways\"}\n", + "\n", + " # --- Trendrichtung per Linear Regression ---\n", + " def linreg_slope(series):\n", + " X = np.arange(len(series)).reshape(-1, 1)\n", + " y = series.values.reshape(-1, 1)\n", + " model = LinearRegression().fit(X, y)\n", + " return model.coef_[0][0]\n", + "\n", + " slope_long = linreg_slope(df[\"close\"].iloc[-50:]) # 50 Balken (~4h)\n", + " slope_short = linreg_slope(df[\"close\"].iloc[-15:]) # 15 Balken (~1h)\n", + "\n", + " # --- Dynamischer Seitwärtsfilter ---\n", + " slope_threshold = slope_factor * atr / df[\"close\"].iloc[-1]\n", + "\n", + " if abs(slope_long) < slope_threshold and abs(slope_short) < slope_threshold:\n", + " return {\"signal\": 0, \"reason\": \"Trend flat → sideways\"}\n", + "\n", + " # --- Trendlogik ---\n", + " trend_standard = \"uptrend\" if slope_long > 0 else \"downtrend\"\n", + " trend_fast = \"uptrend\" if slope_short > 0 else \"downtrend\"\n", + "\n", + " current_price = df[\"close\"].iloc[-1]\n", + "\n", + " # --- Dynamische RRR-Berechnung ---\n", + " atr_norm = atr / current_price # relative Volatilität\n", + " slope_strength = abs(slope_short) # Trendstärke aus Regression\n", + "\n", + " rrr_base = 1.2\n", + " rrr_from_vol = atr_norm * 1500 # skaliert ATR-Einfluss\n", + " rrr_from_slope = slope_strength / slope_threshold # Slope-Einfluss\n", + "\n", + " rrr = rrr_base + rrr_from_vol + rrr_from_slope\n", + " rrr = max(1.2, min(rrr, 3.0)) # Begrenzung\n", + "\n", + " print(f\"[RRR-DEBUG] ATR_norm={atr_norm:.5f} | slope_strength={slope_strength:.5f} | \"\n", + " f\"rrr_vol={rrr_from_vol:.2f} | rrr_slope={rrr_from_slope:.2f} | FINAL_RRR={rrr:.2f}\")\n", + "\n", + " # --- Signale ---\n", + " signal, stop_loss, takeprofit = 0, None, None\n", + " if trend_standard == \"uptrend\" and trend_fast == \"uptrend\":\n", + " signal = 1\n", + " stop_loss = current_price - atr_mult * atr\n", + " takeprofit = current_price + atr_mult * atr * rrr\n", + " print(f\"BUY {symbol} @ {current_price} | TP: {takeprofit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"buy\", stoploss=stop_loss, take_profit=takeprofit)\n", + "\n", + " elif trend_standard == \"downtrend\" and trend_fast == \"downtrend\":\n", + " signal = -1\n", + " stop_loss = current_price + atr_mult * atr\n", + " takeprofit = current_price - atr_mult * atr * rrr\n", + " print(f\"SELL {symbol} @ {current_price} | TP: {takeprofit} | SL: {stop_loss}\")\n", + " market_order(symbol, volume_dict[symbol], \"sell\", stoploss=stop_loss, take_profit=takeprofit)\n", + "\n", + " # --- SL/TP sowohl mit ATR als auch mit Gewinn-Trailing\n", + " # manage_open_trades()\n", + " open_positions = mt.positions_get(symbol=symbol)\n", + " for pos in open_positions:\n", + " atr_value = df[\"atr\"].iloc[-1]\n", + " update_trailing_sl_tp(pos, atr=atr_value, rrr=rrr, atr_mult=atr_mult)\n", + "\n", + " # --- speichern ---\n", + " trend_dict['m5'] = {\"standard\": trend_standard, \"fast\": trend_fast, \"signal\": signal}\n", + "\n", + " return {\n", + " \"signal\": signal,\n", + " \"price\": current_price,\n", + " \"stop_loss\": stop_loss,\n", + " \"take_profit\": takeprofit,\n", + " \"Risk Reward\": rrr,\n", + " \"trends\": trend_dict['m5'],\n", + " \"atr\": atr,\n", + " \"slope_long\": slope_long,\n", + " \"slope_short\": slope_short\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m5\n", + "Pause Trading: 1\n" + ] + }, + { + "data": { + "text/plain": [ + "{'signal': 0, 'reason': 'Trading paused'}" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_m5_trade_signals()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/retracementLevel.ipynb b/retracementLevel.ipynb index 24e4e51..7cff116 100644 --- a/retracementLevel.ipynb +++ b/retracementLevel.ipynb @@ -88,6 +88,7 @@ "outputs": [], "source": [ "symbols = ['XAUUSD']\n", + "#symbols = ['BTCUSD']\n", "\n", "#'BTCUSD', 'ETHUSD', \n", " #'XRPUSD', , 'EURNZD', 'EURUSD'" @@ -517,7 +518,7 @@ "def get_supres_signal(period: str):\n", "\n", "\n", - " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[period], 0, 50)\n", + " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[period], 0, 120)\n", " df = pd.DataFrame(ohlc)\n", " df['time']=pd.to_datetime(df['time'], unit='s')\n", "\n", @@ -530,14 +531,18 @@ " df.resistance.fillna(0, inplace=True)\n", " df = df[(df.support != 0) | (df.resistance != 0)]\n", "\n", - " if df.resistance.iloc[-1] != 0:\n", + " if df.resistance.iloc[-1] != 0 or df.ma3.iloc[-1] > df.close.iloc[-1]:\n", " signal = 'sell'\n", " print(f'sell at: {df.resistance.iloc[-1]}')\n", - " elif df.support.iloc[-1] !=0:\n", + " elif df.support.iloc[-1] !=0 or df.ma3.iloc[-1] < df.close.iloc[-1]:\n", " signal = 'buy'\n", " print(f'buy at: {df.support.iloc[-1]}')\n", + " else:\n", + " signal = 'none'\n", "\n", " return signal\n", + "\n", + "\n", "\n" ] }, @@ -547,7 +552,7 @@ "metadata": {}, "outputs": [], "source": [ - "get_supres_signal('m30')" + "get_supres_signal('m15')" ] }, { @@ -839,7 +844,7 @@ "source": [ "def decide_order():\n", "\n", - " global symbol, volume_dict, periods_dict\n", + " global symbol, volume_dict, periods_dict, trend_dict\n", " \n", "\n", " ## SMA Version 2\n", @@ -849,18 +854,44 @@ " for ts in tsignals:\n", " sma_signals = get_sma(ts)\n", "\n", - " supress_signal = get_supres_signal(ts)\n", - " print(f\"surpress Signal: {supress_signal}\")\n", - " signals.append(supress_signal)\n", - " \n", - " if sma_signals.buy.iloc[-1] == 1: #sma_signals.diff5.tail(2).sum() > 0: \n", - " print(ts, 'buy', sma_signals.diff5.tail(2).sum(), sma_signals.diff10.tail(2).sum())\n", + "\n", + " if sma_signals.buy.iloc[-1] == 1 and sma_signals.sell.iloc[-1] != 1:\n", + " print(sma_signals.buy.iloc[-1] )\n", " signals.append('buy')\n", + " elif sma_signals.sell.iloc[-1] == 1 and sma_signals.buy.iloc[-1] != 1:\n", + " print(sma_signals.sell.iloc[-1])\n", + " signals.append('sell')\n", " else:\n", - " print(ts, 'sell', sma_signals.diff5.tail(2).sum(), sma_signals.diff10.tail(2).sum())\n", " signals.append('sell')\n", "\n", - " \n", + " # support resistance signal\n", + " # supress_signal = get_supres_signal(ts)\n", + " # if supress_signal != 'none':\n", + " # print(f\"surpress Signal: {supress_signal}\")\n", + " # signals.append(supress_signal)\n", + "\n", + " # if sma_signals.ma10.iloc[-1] < sma_signals.close.iloc[-1]: # or sma_signals.buy.iloc[-1] == 1: #sma_signals.diff5.tail(2).sum() > 0: # and sma_signals.buy.iloc[-1] == 1:\n", + " # #print(ts, 'buy', sma_signals.ma10.iloc[-1], sma_signals.close.iloc[-1])\n", + " # signals.append('buy')\n", + " # elif sma_signals.ma10.iloc[-1] > sma_signals.close.iloc[-1]: # or sma_signals.sell.iloc[-1] == 1:\n", + " # #print(ts, 'sell', sma_signals.ma10.iloc[-1], sma_signals.close.iloc[-1])\n", + " # signals.append('sell')\n", + " \n", + " # if sma_signals.ma10.iloc[-1] < sma_signals.ma5.iloc[-1]:# or sma_signals.buy.iloc[-1] == 1: #sma_signals.diff5.tail(2).sum() > 0: # and sma_signals.buy.iloc[-1] == 1:\n", + " # print(ts, 'buy', sma_signals.ma10.iloc[-1], sma_signals.ma5.iloc[-1])\n", + " # signals.append('buy')\n", + " # elif sma_signals.ma10.iloc[-1] > sma_signals.ma5.iloc[-1]: # or sma_signals.sell.iloc[-1] == 1:\n", + " # print(ts, 'sell', sma_signals.ma10.iloc[-1], sma_signals.ma5.iloc[-1])\n", + " # signals.append('sell')\n", + "\n", + " current_period = periods_dict[symbol]\n", + " if trend_dict[current_period[0]] == 'uptrend':\n", + " signals.append('buy')\n", + " #signals.append('buy')\n", + " elif trend_dict[current_period[0]] == 'downtrend':\n", + " signals.append('sell')\n", + " #signals.append('sell')\n", + "\n", "\n", " cbuy = signals.count('buy')\n", " csell = signals.count('sell')\n", @@ -869,7 +900,7 @@ " if cbuy > csell:\n", " signal = 'buy'\n", " print(signal)\n", - " else:\n", + " elif cbuy <= csell:\n", " signal = 'sell'\n", " print(signal)\n", "\n", @@ -963,6 +994,13 @@ "# Trend Detection" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## timefame & trend dictionary" + ] + }, { "cell_type": "code", "execution_count": null, @@ -970,9 +1008,11 @@ "outputs": [], "source": [ "trend_dict = {\n", - " 'm5': '',\n", + " #'m5': '',\n", + " #'m10': '',\n", " 'm15': '',\n", " #'m30': '',\n", + " #'h4': '',\n", "}" ] }, @@ -991,6 +1031,7 @@ " 'm20': mt.TIMEFRAME_M20,\n", " 'm30': mt.TIMEFRAME_M30,\n", " 'h1': mt.TIMEFRAME_H1,\n", + " 'h4': mt.TIMEFRAME_H4,\n", "}\n", "\n", "\n", @@ -1025,7 +1066,7 @@ "\n", " global symbol\n", "\n", - " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[periode], 0, 200)\n", + " ohlc = mt.copy_rates_from_pos(symbol, timeframes_dict[periode], 0, 300)\n", " df = pd.DataFrame(ohlc)\n", " df['time']=pd.to_datetime(df['time'], unit='s')\n", "\n", @@ -1046,6 +1087,17 @@ " return df" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Parameter | Wirkung |\n", + "| ------------ | ------------------------------------------- |\n", + "| `distance` | Wie **nah beieinander** Peaks liegen dürfen |\n", + "| `width` | Wie **breit/flach** ein Peak sein muss |\n", + "| `prominence` | Wie **stark auffällig** ein Peak sein muss |\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1069,10 +1121,10 @@ "\n", " atr = df2.atr.iloc[-1] # all the first atrs are NaN\n", "\n", - " peaks_idx, _ = find_peaks(df2.close_smooth, distance = 15, \n", + " peaks_idx, _ = find_peaks(df2.close_smooth, distance = 2, \n", " width = 3, prominence=atr)\n", "\n", - " troughs_idx, _ = find_peaks(-1*df2.close_smooth, distance = 15, \n", + " troughs_idx, _ = find_peaks(-1*df2.close_smooth, distance = 2, \n", " width = 3, prominence=atr)\n", "\n", " peaks, = ax.plot(df2.index[peaks_idx], df2.close_smooth.iloc[peaks_idx], \\\n", @@ -1096,6 +1148,15 @@ "\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_trend('m15')" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1135,14 +1196,26 @@ "metadata": {}, "outputs": [], "source": [ - "pause_trading, trend_dict, periods_dict" + "pause_trading, trend_dict, periods_dict, symbols[0]" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'set_trend' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m set_trend()\n", + "\u001b[1;31mNameError\u001b[0m: name 'set_trend' is not defined" + ] + } + ], "source": [ "set_trend()" ] @@ -1153,7 +1226,7 @@ "metadata": {}, "outputs": [], "source": [ - "trend_dict" + "trend_dict[periods_dict[symbol][0]]" ] }, { @@ -1191,6 +1264,7 @@ "scheduler.add_job(set_symbol, 'interval', minutes=30)\n", "scheduler.add_job(set_trend, 'interval', minutes=1)\n", "\n", + "#scheduler.add_job(decide_order, 'interval', minutes=1)\n", "scheduler.add_job(decide_order, 'cron', year=\"*\", month=\"*\", day_of_week=\"mon, tue, wed, thu, fri\", hour='0-23', minute='*') #cron\n", "\n", "#scheduler.add_job(export_marketview, 'cron', year=\"*\", month='*', day_of_week='mon, tue, wed; thu, fri', hour='8-22', minute=00)\n", @@ -1284,29 +1358,29 @@ " df = pd.DataFrame(sma)\n", " df['time']=pd.to_datetime(df['time'], unit='s')\n", " df['ma5'] = df['close'].rolling(3).mean()\n", - " df['ma10'] = df['close'].rolling(15).mean()\n", + " df['ma10'] = df['close'].rolling(5).mean()\n", " df['diffclose'] = df['close'].diff()\n", " df['diff5'] = df['ma5'].diff()\n", " df['diff10'] = df['ma10'].diff()\n", - " df['ema'] = df['close'].ewm(span=14, adjust=False).mean()\n", + " df['ema'] = df['close'].ewm(span=5, adjust=False).mean()\n", "\n", "\n", - " support = df[df.low == df.low.rolling(5, center=True).min()].low\n", - " resistance = df[df.high == df.high.rolling(5, center=True).max()].high\n", + " support = df[df.low == df.low.rolling(3, center=True).min()].low\n", + " resistance = df[df.high == df.high.rolling(3, center=True).max()].high\n", " df['resistance'] = resistance\n", " df['support'] = support\n", " df.support.fillna(0, inplace=True)\n", " df.resistance.fillna(0, inplace=True)\n", " df.dropna()\n", - " df = df[['time','open', 'close', 'low', 'ma5', 'ma10', 'diffclose','diff5', 'diff10', 'ema', 'resistance', 'support']]\n", + " #df = df[['time','open', 'close', 'low', 'ma5', 'ma10', 'diffclose','diff5', 'diff10', 'ema', 'resistance', 'support', 'atr']]\n", "\n", " buy = []\n", " sell = []\n", "\n", " for i in range (len(df)):\n", - " if df.ma5.iloc[i] > df.ema.iloc[i]: #and df.ma5[i-1] < df.ma10.iloc[i-1]:\n", + " if df.close.iloc[i] > df.ma5.iloc[i]: #> df.ma10.iloc[i]: #and df.ma5[i-1] < df.ma10.iloc[i-1]:\n", " buy.append(i)\n", - " elif df.ma5.iloc[i] < df.ema.iloc[i]: #and df.ma5[i-1] > df.ma10.iloc[i-1]:\n", + " elif df.close.iloc[i] < df.ma5.iloc[i]: #< df.ma10.iloc[i]: #and df.ma5[i-1] > df.ma10.iloc[i-1]:\n", " sell.append(i)\n", "\n", " buy, sell\n", @@ -1332,7 +1406,7 @@ "outputs": [], "source": [ "sma = get_sma_dev('m15')\n", - "sma.tail(50)\n" + "sma.tail(10)\n" ] }, { @@ -1341,8 +1415,20 @@ "metadata": {}, "outputs": [], "source": [ - "periods_dict['XAUUSD']\n", - "sma.close.tail(10)" + "df = sma\n", + "plt.figure(figsize=(12,5))\n", + "plt.plot(df['close'], label='Close Price', c='blue', alpha=0.5)\n", + "plt.plot(df['ma5'], label='MA5', c='r', alpha=0.9)\n", + "#plt.plot(df['ma10'], label='MA10', c='y', alpha=0.9)\n", + "plt.plot(df['ema'], label='EMA', c='green', alpha=0.9)\n", + "plt.scatter(df[df.buy == 1].index, df[df.buy == 1]['close'], marker='^', color='g', s=100)\n", + "plt.scatter(df[df.sell == 1].index, df[df.sell == 1]['close'], marker='v', color='r', s=100)\n", + "plt.scatter(df[df.support != 0].index, df[df.support != 0]['close'], marker='o', color='orange', s=100)\n", + "plt.scatter(df[df.resistance != 0].index, df[df.resistance != 0]['close'], marker='x', color='black', s=100)\n", + "\n", + "\n", + "plt.legend()\n", + "plt.show()" ] }, { @@ -1351,17 +1437,34 @@ "metadata": {}, "outputs": [], "source": [ - "tsignals = ['m30', 'm15', 'm5', 'm1']\n", + "tsignals = ['m15']\n", "signals = []\n", "\n", "for ts in tsignals:\n", - " sma_signals = get_sma(ts)\n", - " if sma_signals.diff5.tail(2).sum() > 0: # and sma_signals.buy.iloc[-1] == 1:\n", - " print(ts, 'buy', sma_signals.diff5.tail(2).sum(), sma_signals.diff10.tail(2).sum())\n", + " sma_signals = get_sma_dev(ts)\n", + "\n", + " if sma_signals.buy.iloc[-1] == 1 and sma_signals.sell.iloc[-1] != 1:\n", + " print(sma_signals.buy.iloc[-1] )\n", " signals.append('buy')\n", - " else:\n", - " print(ts, 'sell', sma_signals.diff5.tail(2).sum(), sma_signals.diff10.tail(2).sum())\n", + " elif sma_signals.sell.iloc[-1] == 1 and sma_signals.buy.iloc[-1] != 1:\n", + " print(sma_signals.sell.iloc[-1])\n", " signals.append('sell')\n", + " else:\n", + " signals.append('sell')\n", + " \n", + " # if sma_signals.ma10.iloc[-1] < sma_signals.close.iloc[-1]:# or sma_signals.buy.iloc[-1] == 1: #sma_signals.diff5.tail(2).sum() > 0: # and sma_signals.buy.iloc[-1] == 1:\n", + " # print(ts, 'buy', sma_signals.ma10.iloc[-1], sma_signals.close.iloc[-1])\n", + " # signals.append('buy')\n", + " # elif sma_signals.ma10.iloc[-1] > sma_signals.close.iloc[-1]: # or sma_signals.sell.iloc[-1] == 1:\n", + " # print(ts, 'sell', sma_signals.ma10.iloc[-1], sma_signals.close.iloc[-1])\n", + " # signals.append('sell')\n", + "\n", + " # if sma_signals.ma10.iloc[-1] < sma_signals.ma5.iloc[-1]:# or sma_signals.buy.iloc[-1] == 1: #sma_signals.diff5.tail(2).sum() > 0: # and sma_signals.buy.iloc[-1] == 1:\n", + " # print(ts, 'buy', sma_signals.ma10.iloc[-1], sma_signals.ma5.iloc[-1])\n", + " # signals.append('buy')\n", + " # elif sma_signals.ma10.iloc[-1] > sma_signals.ma5.iloc[-1]: # or sma_signals.sell.iloc[-1] == 1:\n", + " # print(ts, 'sell', sma_signals.ma10.iloc[-1], sma_signals.ma5.iloc[-1])\n", + " # signals.append('sell')\n", "\n", "cbuy = signals.count('buy')\n", "csell = signals.count('sell')\n", @@ -1375,11 +1478,21 @@ " print(csell)\n", "\n", "\n", - "signal\n", + "signal, signals\n", "# sma_signals = get_sma('m15')\n", "# df = sma_signals" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "periods_dict['XAUUSD']\n", + "sma.close.tail(10)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1406,24 +1519,6 @@ "\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = sma\n", - "plt.figure(figsize=(12,5))\n", - "plt.plot(df['close'], label='Asset Price', c='blue', alpha=0.5)\n", - "plt.plot(df['ma5'], label='MA5', c='r', alpha=0.9)\n", - "plt.plot(df['ma10'], label='MA10', c='y', alpha=0.9)\n", - "plt.plot(df['ema'], label='EMA', c='green', alpha=0.9)\n", - "plt.scatter(df[df.buy == 1].index, df[df.buy == 1]['close'], marker='^', color='g', s=100)\n", - "plt.scatter(df[df.sell == 1].index, df[df.sell == 1]['close'], marker='v', color='r', s=100)\n", - "plt.legend()\n", - "plt.show()" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1482,8 +1577,8 @@ "df['support'] = support\n", "df.support.fillna(0, inplace=True)\n", "df.resistance.fillna(0, inplace=True)\n", - "df = df[(df.support != 0) | (df.resistance != 0)]\n", - "df\n" + "#df = df[(df.support != 0) | (df.resistance != 0)]\n", + "df.tail(50)\n" ] }, { @@ -1492,14 +1587,16 @@ "metadata": {}, "outputs": [], "source": [ - "if df.resistance.iloc[-1] != 0:\n", + "if df.resistance.iloc[-1] != 0 or df.ma3.iloc[-1] > df.close.iloc[-1]:\n", " signal = 'sell'\n", " print(f'sell at: {df.resistance.iloc[-1]}')\n", - "elif df.support.iloc[-1] !=0:\n", + "elif df.support.iloc[-1] !=0 or df.ma3.iloc[-1] < df.close.iloc[-1]:\n", " signal = 'buy'\n", " print(f'buy at: {df.support.iloc[-1]}')\n", "else:\n", - " signal = 'none'\n" + " signal = 'none'\n", + "\n", + "print(signal)" ] }, {