Загрузка данных


import MetaTrader5 as mt5
import pandas as pd
import numpy as np
import time
from datetime import datetime

# ====================== НАСТРОЙКИ ======================
SYMBOLS_BASE = ["EURUSD", "GBPUSD", "USDJPY", "AUDUSD", "USDCAD", "NZDUSD"]
TIMEFRAME_TREND = mt5.TIMEFRAME_H1      # тренд
TIMEFRAME_ENTRY = mt5.TIMEFRAME_M15     # вход (чаще сигналы)
EMA_FAST = 20
EMA_SLOW = 50
RISK_PERCENT = 0.7                      # риск на сделку %
SL_ATR_MULT = 1.5
TP_RR = 1.8
MAGIC = 20261022
# =======================================================

def log(msg):
    print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")

def initialize():
    if not mt5.initialize():
        log(f"Ошибка инициализации MT5: {mt5.last_error()}")
        return False
    log("MT5 успешно подключен")
    account = mt5.account_info()
    if account:
        log(f"Счёт: {account.login} | Баланс: {account.balance:.2f} | Сервер: {account.server}")
    return True

def find_symbol(base_name):
    """Ищет реальный символ у брокера (EURUSD, EURUSD.a, EURUSDm и т.д.)"""
    symbols = mt5.symbols_get()
    if symbols is None:
        return None
    
    candidates = [
        base_name,
        base_name + ".a",
        base_name + "m",
        base_name + ".m",
        base_name + "pro",
        base_name + ".pro",
        base_name + "#",
    ]
    
    available = {s.name: s for s in symbols}
    
    for name in candidates:
        if name in available and available[name].visible:
            return name
        # пробуем включить
        if name in available:
            mt5.symbol_select(name, True)
            return name
    return None

def get_df(symbol, timeframe, bars=300):
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, bars)
    if rates is None or len(rates) < 100:
        return None
    df = pd.DataFrame(rates)
    df['ema_fast'] = df['close'].ewm(span=EMA_FAST, adjust=False).mean()
    df['ema_slow'] = df['close'].ewm(span=EMA_SLOW, adjust=False).mean()
    
    # ATR
    high_low = df['high'] - df['low']
    high_close = np.abs(df['high'] - df['close'].shift())
    low_close = np.abs(df['low'] - df['close'].shift())
    tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
    df['atr'] = tr.rolling(14).mean()
    return df

def get_trend(symbol):
    df = get_df(symbol, TIMEFRAME_TREND)
    if df is None:
        return None
    last = df.iloc[-1]
    if last['close'] > last['ema_slow'] and last['ema_fast'] > last['ema_slow']:
        return "bull"
    elif last['close'] < last['ema_slow'] and last['ema_fast'] < last['ema_slow']:
        return "bear"
    return "flat"

def check_signal(symbol, trend):
    df = get_df(symbol, TIMEFRAME_ENTRY)
    if df is None:
        return None
    
    prev = df.iloc[-2]
    last = df.iloc[-1]
    
    # Быстрый кроссовер
    if trend == "bull":
        if prev['ema_fast'] <= prev['ema_slow'] and last['ema_fast'] > last['ema_slow']:
            return "buy"
    elif trend == "bear":
        if prev['ema_fast'] >= prev['ema_slow'] and last['ema_fast'] < last['ema_slow']:
            return "sell"
    return None

def calculate_lot(symbol, sl_distance_price):
    account = mt5.account_info()
    if account is None:
        return 0.01
    
    risk_money = account.balance * (RISK_PERCENT / 100.0)
    symbol_info = mt5.symbol_info(symbol)
    if symbol_info is None:
        return 0.01
    
    tick_value = symbol_info.trade_tick_value
    tick_size = symbol_info.trade_tick_size
    if tick_size == 0 or tick_value == 0:
        return 0.01
    
    points = sl_distance_price / tick_size
    if points == 0:
        return 0.01
    
    lot = risk_money / (points * tick_value)
    lot = max(symbol_info.volume_min, min(lot, symbol_info.volume_max))
    lot = round(lot / symbol_info.volume_step) * symbol_info.volume_step
    return round(lot, 2)

def has_position(symbol):
    positions = mt5.positions_get(symbol=symbol)
    if not positions:
        return False
    for p in positions:
        if p.magic == MAGIC:
            return True
    return False

def open_trade(symbol, signal):
    if has_position(symbol):
        log(f"{symbol}: уже есть позиция, пропускаем")
        return
    
    df = get_df(symbol, TIMEFRAME_ENTRY)
    if df is None:
        return
    
    atr = df['atr'].iloc[-1]
    tick = mt5.symbol_info_tick(symbol)
    if tick is None:
        log(f"{symbol}: не удалось получить тик")
        return
    
    if signal == "buy":
        price = tick.ask
        sl = price - atr * SL_ATR_MULT
        tp = price + (price - sl) * TP_RR
        order_type = mt5.ORDER_TYPE_BUY
    else:
        price = tick.bid
        sl = price + atr * SL_ATR_MULT
        tp = price - (sl - price) * TP_RR
        order_type = mt5.ORDER_TYPE_SELL
    
    lot = calculate_lot(symbol, abs(price - sl))
    
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": order_type,
        "price": price,
        "sl": round(sl, 5),
        "tp": round(tp, 5),
        "deviation": 30,
        "magic": MAGIC,
        "comment": f"Bot {signal}",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    
    result = mt5.order_send(request)
    if result.retcode == mt5.TRADE_RETCODE_DONE:
        log(f"✓ ОТКРЫЛ {signal.upper()} {symbol} | лот {lot} | цена {price:.5f} | SL {sl:.5f} | TP {tp:.5f}")
    else:
        log(f"✗ Ошибка открытия {symbol}: {result.retcode} — {result.comment}")

def main():
    if not initialize():
        return
    
    log("=" * 55)
    log("Бот запущен | M15 вход + H1 тренд | подробные логи")
    log("=" * 55)
    
    # Находим реальные символы
    real_symbols = {}
    for base in SYMBOLS_BASE:
        found = find_symbol(base)
        if found:
            real_symbols[base] = found
            log(f"Символ найден: {base} → {found}")
        else:
            log(f"Символ НЕ найден: {base}")
    
    if not real_symbols:
        log("Не найдено ни одного символа. Проверь брокера.")
        return
    
    while True:
        try:
            log("-" * 40)
            for base, symbol in real_symbols.items():
                trend = get_trend(symbol)
                log(f"{symbol}: тренд = {trend}")
                
                if trend in ["bull", "bear"]:
                    signal = check_signal(symbol, trend)
                    if signal:
                        log(f"{symbol}: !!! СИГНАЛ {signal.upper()} !!!")
                        open_trade(symbol, signal)
                    else:
                        log(f"{symbol}: сигнала нет")
                else:
                    log(f"{symbol}: боковик, пропускаем")
            
            time.sleep(20)  # проверка каждые 20 секунд
            
        except Exception as e:
            log(f"Ошибка в цикле: {e}")
            time.sleep(10)

if __name__ == "__main__":
    main()