2061 lines
65 KiB
Plaintext
2061 lines
65 KiB
Plaintext
{
|
||||
|
|
"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": [
|
|||
|
|
"<div>\n",
|
|||
|
|
"<style scoped>\n",
|
|||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|||
|
|
" vertical-align: middle;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe tbody tr th {\n",
|
|||
|
|
" vertical-align: top;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe thead th {\n",
|
|||
|
|
" text-align: right;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"</style>\n",
|
|||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|||
|
|
" <thead>\n",
|
|||
|
|
" <tr style=\"text-align: right;\">\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th>open</th>\n",
|
|||
|
|
" <th>high</th>\n",
|
|||
|
|
" <th>low</th>\n",
|
|||
|
|
" <th>close</th>\n",
|
|||
|
|
" <th>tick_volume</th>\n",
|
|||
|
|
" <th>spread</th>\n",
|
|||
|
|
" <th>real_volume</th>\n",
|
|||
|
|
" <th>atr</th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>time</th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </thead>\n",
|
|||
|
|
" <tbody>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-28 22:00:00</th>\n",
|
|||
|
|
" <td>3420.04</td>\n",
|
|||
|
|
" <td>3420.35</td>\n",
|
|||
|
|
" <td>3419.77</td>\n",
|
|||
|
|
" <td>3419.85</td>\n",
|
|||
|
|
" <td>1045</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-28 22:05:00</th>\n",
|
|||
|
|
" <td>3419.82</td>\n",
|
|||
|
|
" <td>3420.01</td>\n",
|
|||
|
|
" <td>3418.74</td>\n",
|
|||
|
|
" <td>3418.90</td>\n",
|
|||
|
|
" <td>1057</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-28 22:10:00</th>\n",
|
|||
|
|
" <td>3418.93</td>\n",
|
|||
|
|
" <td>3419.20</td>\n",
|
|||
|
|
" <td>3418.27</td>\n",
|
|||
|
|
" <td>3418.62</td>\n",
|
|||
|
|
" <td>1003</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-28 22:15:00</th>\n",
|
|||
|
|
" <td>3418.62</td>\n",
|
|||
|
|
" <td>3419.81</td>\n",
|
|||
|
|
" <td>3418.55</td>\n",
|
|||
|
|
" <td>3419.69</td>\n",
|
|||
|
|
" <td>1218</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-28 22:20:00</th>\n",
|
|||
|
|
" <td>3419.67</td>\n",
|
|||
|
|
" <td>3420.01</td>\n",
|
|||
|
|
" <td>3419.15</td>\n",
|
|||
|
|
" <td>3419.17</td>\n",
|
|||
|
|
" <td>956</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>...</th>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-29 23:35:00</th>\n",
|
|||
|
|
" <td>3447.78</td>\n",
|
|||
|
|
" <td>3448.55</td>\n",
|
|||
|
|
" <td>3447.18</td>\n",
|
|||
|
|
" <td>3448.21</td>\n",
|
|||
|
|
" <td>546</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>1.968904</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-29 23:40:00</th>\n",
|
|||
|
|
" <td>3448.21</td>\n",
|
|||
|
|
" <td>3449.35</td>\n",
|
|||
|
|
" <td>3447.78</td>\n",
|
|||
|
|
" <td>3449.17</td>\n",
|
|||
|
|
" <td>421</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>1.961315</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-29 23:45:00</th>\n",
|
|||
|
|
" <td>3449.15</td>\n",
|
|||
|
|
" <td>3449.18</td>\n",
|
|||
|
|
" <td>3447.64</td>\n",
|
|||
|
|
" <td>3447.90</td>\n",
|
|||
|
|
" <td>578</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>1.955341</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-29 23:50:00</th>\n",
|
|||
|
|
" <td>3447.86</td>\n",
|
|||
|
|
" <td>3448.36</td>\n",
|
|||
|
|
" <td>3447.68</td>\n",
|
|||
|
|
" <td>3448.22</td>\n",
|
|||
|
|
" <td>467</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>1.947173</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2025-08-29 23:55:00</th>\n",
|
|||
|
|
" <td>3448.20</td>\n",
|
|||
|
|
" <td>3448.91</td>\n",
|
|||
|
|
" <td>3447.97</td>\n",
|
|||
|
|
" <td>3448.87</td>\n",
|
|||
|
|
" <td>228</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>1.938756</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </tbody>\n",
|
|||
|
|
"</table>\n",
|
|||
|
|
"<p>300 rows × 8 columns</p>\n",
|
|||
|
|
"</div>"
|
|||
|
|
],
|
|||
|
|
"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": [
|
|||
|
|
"<div>\n",
|
|||
|
|
"<style scoped>\n",
|
|||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|||
|
|
" vertical-align: middle;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe tbody tr th {\n",
|
|||
|
|
" vertical-align: top;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe thead th {\n",
|
|||
|
|
" text-align: right;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"</style>\n",
|
|||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|||
|
|
" <thead>\n",
|
|||
|
|
" <tr style=\"text-align: right;\">\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th>time</th>\n",
|
|||
|
|
" <th>open</th>\n",
|
|||
|
|
" <th>high</th>\n",
|
|||
|
|
" <th>low</th>\n",
|
|||
|
|
" <th>close</th>\n",
|
|||
|
|
" <th>tick_volume</th>\n",
|
|||
|
|
" <th>spread</th>\n",
|
|||
|
|
" <th>real_volume</th>\n",
|
|||
|
|
" <th>ema21</th>\n",
|
|||
|
|
" <th>ema50</th>\n",
|
|||
|
|
" <th>rsi9</th>\n",
|
|||
|
|
" <th>rsi14</th>\n",
|
|||
|
|
" <th>trend</th>\n",
|
|||
|
|
" <th>atr</th>\n",
|
|||
|
|
" <th>adx</th>\n",
|
|||
|
|
" <th>fast_signal</th>\n",
|
|||
|
|
" <th>standard_signal</th>\n",
|
|||
|
|
" <th>optimized_signal</th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </thead>\n",
|
|||
|
|
" <tbody>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>0</th>\n",
|
|||
|
|
" <td>2025-08-28 05:25:00</td>\n",
|
|||
|
|
" <td>3386.52</td>\n",
|
|||
|
|
" <td>3386.74</td>\n",
|
|||
|
|
" <td>3385.71</td>\n",
|
|||
|
|
" <td>3386.64</td>\n",
|
|||
|
|
" <td>714</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3386.640000</td>\n",
|
|||
|
|
" <td>3386.640000</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>3385.220875</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>1</th>\n",
|
|||
|
|
" <td>2025-08-28 05:30:00</td>\n",
|
|||
|
|
" <td>3386.75</td>\n",
|
|||
|
|
" <td>3386.98</td>\n",
|
|||
|
|
" <td>3385.81</td>\n",
|
|||
|
|
" <td>3385.85</td>\n",
|
|||
|
|
" <td>985</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3386.113333</td>\n",
|
|||
|
|
" <td>3386.201111</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>3386.775285</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2</th>\n",
|
|||
|
|
" <td>2025-08-28 05:35:00</td>\n",
|
|||
|
|
" <td>3385.86</td>\n",
|
|||
|
|
" <td>3387.38</td>\n",
|
|||
|
|
" <td>3384.59</td>\n",
|
|||
|
|
" <td>3387.17</td>\n",
|
|||
|
|
" <td>1151</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3386.717143</td>\n",
|
|||
|
|
" <td>3386.598197</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>3388.065491</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>3</th>\n",
|
|||
|
|
" <td>2025-08-28 05:40:00</td>\n",
|
|||
|
|
" <td>3387.12</td>\n",
|
|||
|
|
" <td>3388.36</td>\n",
|
|||
|
|
" <td>3386.82</td>\n",
|
|||
|
|
" <td>3388.18</td>\n",
|
|||
|
|
" <td>798</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3387.497333</td>\n",
|
|||
|
|
" <td>3387.134038</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>3389.112151</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>4</th>\n",
|
|||
|
|
" <td>2025-08-28 05:45:00</td>\n",
|
|||
|
|
" <td>3388.16</td>\n",
|
|||
|
|
" <td>3390.56</td>\n",
|
|||
|
|
" <td>3387.94</td>\n",
|
|||
|
|
" <td>3390.46</td>\n",
|
|||
|
|
" <td>947</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3389.026452</td>\n",
|
|||
|
|
" <td>3388.123436</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>3389.935928</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>NaN</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>...</th>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" <td>...</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>495</th>\n",
|
|||
|
|
" <td>2025-08-29 23:40:00</td>\n",
|
|||
|
|
" <td>3448.21</td>\n",
|
|||
|
|
" <td>3449.35</td>\n",
|
|||
|
|
" <td>3447.78</td>\n",
|
|||
|
|
" <td>3449.17</td>\n",
|
|||
|
|
" <td>421</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3448.743230</td>\n",
|
|||
|
|
" <td>3448.456881</td>\n",
|
|||
|
|
" <td>56.591716</td>\n",
|
|||
|
|
" <td>56.452748</td>\n",
|
|||
|
|
" <td>3448.267585</td>\n",
|
|||
|
|
" <td>2.002968</td>\n",
|
|||
|
|
" <td>15.874639</td>\n",
|
|||
|
|
" <td>1</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>496</th>\n",
|
|||
|
|
" <td>2025-08-29 23:45:00</td>\n",
|
|||
|
|
" <td>3449.15</td>\n",
|
|||
|
|
" <td>3449.18</td>\n",
|
|||
|
|
" <td>3447.64</td>\n",
|
|||
|
|
" <td>3447.90</td>\n",
|
|||
|
|
" <td>578</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3448.321615</td>\n",
|
|||
|
|
" <td>3448.345505</td>\n",
|
|||
|
|
" <td>50.150670</td>\n",
|
|||
|
|
" <td>52.209309</td>\n",
|
|||
|
|
" <td>3447.941698</td>\n",
|
|||
|
|
" <td>1.969899</td>\n",
|
|||
|
|
" <td>15.547755</td>\n",
|
|||
|
|
" <td>-1</td>\n",
|
|||
|
|
" <td>-1</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>497</th>\n",
|
|||
|
|
" <td>2025-08-29 23:50:00</td>\n",
|
|||
|
|
" <td>3447.86</td>\n",
|
|||
|
|
" <td>3448.36</td>\n",
|
|||
|
|
" <td>3447.68</td>\n",
|
|||
|
|
" <td>3448.22</td>\n",
|
|||
|
|
" <td>467</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3448.270808</td>\n",
|
|||
|
|
" <td>3448.320404</td>\n",
|
|||
|
|
" <td>51.708684</td>\n",
|
|||
|
|
" <td>53.164605</td>\n",
|
|||
|
|
" <td>3447.570685</td>\n",
|
|||
|
|
" <td>1.877764</td>\n",
|
|||
|
|
" <td>15.244220</td>\n",
|
|||
|
|
" <td>-1</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>498</th>\n",
|
|||
|
|
" <td>2025-08-29 23:55:00</td>\n",
|
|||
|
|
" <td>3448.20</td>\n",
|
|||
|
|
" <td>3448.91</td>\n",
|
|||
|
|
" <td>3447.97</td>\n",
|
|||
|
|
" <td>3448.87</td>\n",
|
|||
|
|
" <td>228</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3448.570404</td>\n",
|
|||
|
|
" <td>3448.430323</td>\n",
|
|||
|
|
" <td>54.927801</td>\n",
|
|||
|
|
" <td>55.126747</td>\n",
|
|||
|
|
" <td>3447.156651</td>\n",
|
|||
|
|
" <td>1.810780</td>\n",
|
|||
|
|
" <td>15.232676</td>\n",
|
|||
|
|
" <td>1</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>499</th>\n",
|
|||
|
|
" <td>2025-09-01 01:00:00</td>\n",
|
|||
|
|
" <td>3444.73</td>\n",
|
|||
|
|
" <td>3449.27</td>\n",
|
|||
|
|
" <td>3444.67</td>\n",
|
|||
|
|
" <td>3445.14</td>\n",
|
|||
|
|
" <td>245</td>\n",
|
|||
|
|
" <td>20</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" <td>3446.855202</td>\n",
|
|||
|
|
" <td>3447.772258</td>\n",
|
|||
|
|
" <td>38.401814</td>\n",
|
|||
|
|
" <td>43.789528</td>\n",
|
|||
|
|
" <td>3446.701703</td>\n",
|
|||
|
|
" <td>2.010010</td>\n",
|
|||
|
|
" <td>14.843679</td>\n",
|
|||
|
|
" <td>-1</td>\n",
|
|||
|
|
" <td>-1</td>\n",
|
|||
|
|
" <td>0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </tbody>\n",
|
|||
|
|
"</table>\n",
|
|||
|
|
"<p>500 rows × 18 columns</p>\n",
|
|||
|
|
"</div>"
|
|||
|
|
],
|
|||
|
|
"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
|
|||
|
|
}
|