199 lines
No EOL
8.3 KiB
Python
199 lines
No EOL
8.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Trading Bot Simulation
|
|
|
|
Automatically generated by Colab.
|
|
|
|
Original file is located at
|
|
https://colab.research.google.com/drive/1xQA5F3HvFfWWO3Xe2PKXEM68FFx_s-rc
|
|
"""
|
|
|
|
import numpy as np
|
|
import time
|
|
# NOTE: In a real environment, you must install the MetaTrader5 package:
|
|
# pip install MetaTrader5
|
|
# import MetaTrader5 as mt5
|
|
|
|
# --- MOCK MT5 LIBRARY & CONFIGURATION ---
|
|
# The functions below are STUBS (placeholders) that mimic the real MT5 library behavior.
|
|
# Replace the comments with your actual MT5 connection logic and credentials.
|
|
|
|
# Strategy parameters
|
|
SYMBOL = "EURUSD"
|
|
TIMEFRAME = "M15" # E.g., 15-minute bars
|
|
SHORT_WINDOW = 5
|
|
LONG_WINDOW = 15
|
|
VOLUME = 0.1 # Trading volume (lot size)
|
|
|
|
def mt5_initialize_connection(login, password, server):
|
|
"""Initializes connection to MT5 terminal."""
|
|
print("Connecting to MT5 terminal...")
|
|
# if not mt5.initialize(login=login, password=password, server=server):
|
|
# print(f"Failed to initialize MT5: {mt5.last_error()}")
|
|
# return False
|
|
# print("MT5 connection successful.")
|
|
return True
|
|
|
|
def mt5_fetch_data(symbol, period_size, count):
|
|
"""Fetches the last 'count' bars of data from MT5."""
|
|
# This mock data simulates fetching the last 30 closing prices
|
|
print(f"Fetching {count} historical bars for {symbol}...")
|
|
|
|
# In a real bot, you'd use:
|
|
# rates = mt5.copy_rates_from_pos(symbol, period_size, 0, count)
|
|
# df = pd.DataFrame(rates)
|
|
# df['time'] = pd.to_datetime(df['time'], unit='s')
|
|
# return df['close'].to_numpy() # We only need the closing prices for SMA
|
|
|
|
# Using the simulation data for demonstration:
|
|
PRICE_DATA = [
|
|
100.00, 101.50, 102.10, 103.00, 105.50, 104.90, 106.30, 107.80, 108.20, 107.50,
|
|
110.00, 112.40, 115.80, 114.30, 113.10, 116.70, 118.90, 120.00, 122.50, 121.10,
|
|
125.00, 126.90, 124.70, 128.00, 130.40, 127.80, 126.10, 125.50, 129.00, 132.00
|
|
]
|
|
return np.array(PRICE_DATA)
|
|
|
|
def mt5_send_order(symbol, direction, volume, price_limit=None):
|
|
"""Mocks sending a market or limit order to MT5."""
|
|
order_type = "BUY" if direction == 1 else "SELL"
|
|
# This is where your actual order execution code goes using mt5.order_send()
|
|
|
|
# In a real bot, you'd calculate price, deviation, and create a request dictionary:
|
|
# request = {
|
|
# "action": mt5.TRADE_ACTION_DEAL,
|
|
# "symbol": symbol,
|
|
# "volume": volume,
|
|
# "type": mt5.ORDER_TYPE_BUY if direction == 1 else mt5.ORDER_TYPE_SELL,
|
|
# "price": mt5.symbol_info_tick(symbol).ask if direction == 1 else mt5.symbol_info_tick(symbol).bid,
|
|
# "deviation": 20, # Max price slippage
|
|
# "magic": 202409,
|
|
# "comment": "SMA Crossover Bot",
|
|
# "type_time": mt5.ORDER_TIME_GTC,
|
|
# "type_filling": mt5.ORDER_FILLING_FOC,
|
|
# }
|
|
# result = mt5.order_send(request)
|
|
|
|
print(f"\n[ORDER SENT] --- {order_type} {volume} lots of {symbol}")
|
|
# print(f"MT5 API Response: {result}")
|
|
|
|
return True
|
|
|
|
# --- CORE LOGIC FUNCTIONS (RETAINED FOR TECHNICAL ANALYSIS) ---
|
|
|
|
def calculate_sma(data, window):
|
|
"""Calculates the Simple Moving Average (SMA) for a given window."""
|
|
weights = np.repeat(1.0, window) / window
|
|
smas = np.convolve(data, weights, 'valid')
|
|
padding = np.full(window - 1, np.nan)
|
|
return np.concatenate((padding, smas))
|
|
|
|
def generate_signals(prices, short_window, long_window):
|
|
"""Generates buy (1) and sell (-1) signals based on SMA Crossover."""
|
|
# We only need the last two values of the SMAs to detect a recent crossover
|
|
prices_array = np.array(prices)
|
|
short_sma = calculate_sma(prices_array, short_window)
|
|
long_sma = calculate_sma(prices_array, long_window)
|
|
|
|
# Check for non-NaN values
|
|
if np.isnan(short_sma[-1]) or np.isnan(long_sma[-1]) or \
|
|
np.isnan(short_sma[-2]) or np.isnan(long_sma[-2]):
|
|
return 0, short_sma, long_sma # No signal if data is insufficient
|
|
|
|
# Bullish Crossover (BUY signal)
|
|
if short_sma[-1] > long_sma[-1] and short_sma[-2] <= long_sma[-2]:
|
|
return 1, short_sma, long_sma
|
|
|
|
# Bearish Crossover (SELL signal)
|
|
elif short_sma[-1] < long_sma[-1] and short_sma[-2] >= long_sma[-2]:
|
|
return -1, short_sma, long_sma
|
|
|
|
# No Crossover (HOLD signal)
|
|
return 0, short_sma, long_sma
|
|
|
|
# --- LIVE TRADING LOOP ---
|
|
|
|
def live_trading_main(symbol, timeframe, short_window, long_window, volume, interval_seconds=60):
|
|
"""
|
|
Main loop for live trading on MT5.
|
|
NOTE: Replace the mock connection details with your real MT5 credentials.
|
|
"""
|
|
# Replace with your actual credentials
|
|
LOGIN = 12345678
|
|
PASSWORD = "your_password"
|
|
SERVER = "your_server_name"
|
|
|
|
if not mt5_initialize_connection(LOGIN, PASSWORD, SERVER):
|
|
return
|
|
|
|
# The loop runs forever, constantly checking for new data and signals
|
|
print(f"\nStarting live trading loop for {symbol}. Checking every {interval_seconds} seconds...")
|
|
while True:
|
|
try:
|
|
# 1. Fetch data required for the longest moving average (LONG_WINDOW)
|
|
# We need at least LONG_WINDOW bars + 1 previous bar to detect a cross
|
|
DATA_POINTS_TO_FETCH = long_window + 1
|
|
|
|
# Fetch real data (mocked here)
|
|
close_prices = mt5_fetch_data(symbol, timeframe, DATA_POINTS_TO_FETCH)
|
|
|
|
# 2. Generate signal based on the latest data
|
|
signal, short_sma, long_sma = generate_signals(
|
|
close_prices, short_window, long_window
|
|
)
|
|
|
|
current_price = close_prices[-1]
|
|
latest_short_ma = short_sma[-1] if not np.isnan(short_sma[-1]) else 'N/A'
|
|
latest_long_ma = long_sma[-1] if not np.isnan(long_sma[-1]) else 'N/A'
|
|
|
|
print(f"\n[{time.strftime('%H:%M:%S')}] Price: ${current_price:.4f} | SMA({short_window}): {latest_short_ma} | SMA({long_window}): {latest_long_ma} | Signal: {signal}")
|
|
|
|
# 3. Execute Trade based on signal
|
|
if signal == 1:
|
|
# Check for existing open positions before sending BUY order (crucial for MT5)
|
|
# If there are open SELL positions, you'd close them first.
|
|
print(">>> BULLISH CROSSOVER DETECTED. ATTEMPTING TO BUY.")
|
|
mt5_send_order(symbol, 1, volume) # 1 for BUY
|
|
|
|
elif signal == -1:
|
|
# Check for existing open positions before sending SELL order
|
|
# If there are open BUY positions, you'd close them first.
|
|
print(">>> BEARISH CROSSOVER DETECTED. ATTEMPTING TO SELL.")
|
|
mt5_send_order(symbol, -1, volume) # -1 for SELL
|
|
|
|
else:
|
|
print("No signal, holding position.")
|
|
|
|
except Exception as e:
|
|
print(f"An error occurred: {e}")
|
|
# mt5.shutdown() # Uncomment this in a real app to cleanly close the connection
|
|
break # Exit loop on critical error
|
|
|
|
# Wait for the next check cycle
|
|
time.sleep(interval_seconds)
|
|
|
|
|
|
# --- 4. EXECUTION ---
|
|
if __name__ == "__main__":
|
|
# The backtesting functions are now separated from the live trading execution.
|
|
# To run the live trading loop, uncomment the line below.
|
|
# IMPORTANT: You must install the MetaTrader5 library (pip install MetaTrader5)
|
|
# and run this script from a Python environment that is allowed to connect to
|
|
# your running MT5 terminal.
|
|
|
|
print("--- TRADING BOT DRAFT FOR MT5 INTEGRATION ---")
|
|
print("This file contains the SMA logic and the structure for MT5 integration.")
|
|
print("The code below simulates the backtesting process using the mock data.")
|
|
|
|
# Simulated Backtesting (using the old function structure)
|
|
price_history = mt5_fetch_data(SYMBOL, TIMEFRAME, 30)
|
|
signals, short_sma, long_sma = generate_signals(price_history, SHORT_WINDOW, LONG_WINDOW)
|
|
|
|
print("\n--- Backtesting Results (Simulated Data) ---")
|
|
print("Index | Price | Short MA | Long MA | Signal")
|
|
print("--------------------------------------------------")
|
|
for i in range(len(price_history)):
|
|
short_val = f"{short_sma[i]:.2f}" if not np.isnan(short_sma[i]) else 'N/A'
|
|
long_val = f"{long_sma[i]:.2f}" if not np.isnan(long_sma[i]) else 'N/A'
|
|
print(f"{i:5} | {price_history[i]:5.2f} | {short_val:8} | {long_val:7} | {signals[i]:.0f}")
|
|
|
|
# To run the live loop, uncomment this line (after installing MT5):
|
|
# live_trading_main(SYMBOL, TIMEFRAME, SHORT_WINDOW, LONG_WINDOW, VOLUME) |