Skip to main content
Glama

metatrader-mcp-server

calculate_price_targets.py8.48 kB
""" Calculate price targets for take profit and stop loss orders. This module implements a function to calculate price levels for take profit and stop loss orders based on desired profit/loss targets. """ import MetaTrader5 as mt5 from typing import Optional, Union from ..types import OrderType from .calculate_profit import calculate_profit def calculate_price_target( order_type: Union[int, str, OrderType], symbol: str, volume: float, entry_price: float, target: float ) -> Optional[float]: """ Calculate the price level to achieve a desired profit or loss target. Args: order_type: The type of order (BUY or SELL) symbol: Financial instrument name (e.g., "EURUSD") volume: Trading operation volume in lots entry_price: Entry price at which the position is opened target: The profit/loss target to achieve (positive or negative) Positive value: Target profit to achieve Negative value: Maximum loss to limit Returns: float: The price level that achieves the target None: If an error occurred or the target cannot be achieved Examples: # Calculate price for $100 profit on EURUSD BUY position >>> calculate_price_target("BUY", "EURUSD", 0.1, 1.1200, 100.0) 1.1300 # Calculate price to limit losses to $50 on a EURUSD BUY position >>> calculate_price_target("BUY", "EURUSD", 0.1, 1.1200, -50.0) 1.1100 """ # Get symbol info symbol_info = mt5.symbol_info(symbol) if symbol_info is None: print(f"Symbol {symbol} not found") return None # Ensure the symbol is selected in Market Watch if not symbol_info.visible: print(f"Symbol {symbol} is not visible in Market Watch, trying to select it...") if not mt5.symbol_select(symbol, True): print(f"Failed to select {symbol}") return None # Get symbol properties point = symbol_info.point digits = symbol_info.digits tick_size = symbol_info.trade_tick_size tick_value = symbol_info.trade_tick_value contract_size = symbol_info.trade_contract_size # Standardize order type if isinstance(order_type, str): type_code = OrderType.to_code(order_type) if type_code is None: raise ValueError(f"Invalid order type string: {order_type}") elif isinstance(order_type, OrderType): type_code = order_type.value else: type_code = order_type if not OrderType.exists(type_code): raise ValueError(f"Invalid order type code: {type_code}") if type_code not in [OrderType.BUY.value, OrderType.SELL.value]: raise ValueError(f"Only BUY and SELL order types are supported, got {OrderType.to_string(type_code)}") # Binary search approach to find target price is_buy = (type_code == OrderType.BUY.value) # Determine search direction based on order type and target sign # For BUY orders: # - Positive target: price needs to go HIGHER # - Negative target: price needs to go LOWER # For SELL orders: # - Positive target: price needs to go LOWER # - Negative target: price needs to go HIGHER search_higher = (is_buy and target > 0) or (not is_buy and target < 0) # Calculate initial price movement estimation using actual symbol data # We'll estimate how many points of price movement we need to achieve the target # Use tick value to estimate points needed if tick_value and tick_size and tick_value > 0 and tick_size > 0: # Calculate the value of 1 point movement point_value = tick_value / tick_size # Calculate how many points needed for the target if point_value > 0: points_needed = abs(target) / (volume * point_value) # Add a safety factor to ensure we cover the target points_needed *= 1.5 # At least 20 points or 1% of the price min_points = max(20, entry_price * 0.01 / point) points_needed = max(points_needed, min_points) # Calculate price movement price_movement = points_needed * point else: # Fallback if point_value is zero price_movement = entry_price * 0.01 # 1% of entry price else: # Fallback if tick data is missing price_movement = entry_price * 0.01 # 1% of entry price # Set initial bounds based on search direction if search_higher: lower_bound = entry_price upper_bound = entry_price + price_movement else: lower_bound = max(entry_price - price_movement, point) # Don't go below 0 upper_bound = entry_price # Expand bounds until we find a price that gives the target profit max_iterations = 20 iterations = 0 target_found = False while iterations < max_iterations and not target_found: test_price = upper_bound if search_higher else lower_bound test_profit = calculate_profit(type_code, symbol, volume, entry_price, test_price) if test_profit is None: # Failed to calculate profit, try a smaller step price_movement /= 2 if search_higher: upper_bound = entry_price + price_movement else: lower_bound = max(entry_price - price_movement, point) iterations += 1 continue # Check if our bounds contain the target if (target > 0 and test_profit >= target) or (target < 0 and test_profit <= target): target_found = True break # Expand bounds price_movement *= 2 if search_higher: upper_bound = entry_price + price_movement else: lower_bound = max(entry_price - price_movement, point) iterations += 1 if not target_found: print(f"Could not find appropriate price bounds for target {target} on {symbol}") # Last resort - use a very large range if search_higher: upper_bound = entry_price * 2 else: lower_bound = max(entry_price / 2, point) # Binary search to find the exact price tolerance = max(0.01, abs(target * 0.01)) # 1% of target or 0.01 minimum max_binary_iterations = 30 binary_iterations = 0 while (upper_bound - lower_bound) > (point/2) and binary_iterations < max_binary_iterations: mid_price = (lower_bound + upper_bound) / 2 mid_price = round(mid_price, digits) # Skip prices too close to entry price if abs(mid_price - entry_price) < (point * 5): if search_higher: mid_price = entry_price + (10 * point) else: mid_price = entry_price - (10 * point) current_profit = calculate_profit(type_code, symbol, volume, entry_price, mid_price) if current_profit is None: # Failed to calculate profit binary_iterations += 1 # Move toward entry price for stability if search_higher: upper_bound = (mid_price + entry_price) / 2 else: lower_bound = (mid_price + entry_price) / 2 continue # Check if we're close enough to the target if abs(current_profit - target) < tolerance: # Found a close enough match return mid_price # Update bounds based on profit comparison if (target > 0 and current_profit < target) or (target < 0 and current_profit > target): if search_higher: lower_bound = mid_price else: upper_bound = mid_price else: if search_higher: upper_bound = mid_price else: lower_bound = mid_price binary_iterations += 1 # Return our best estimate result = (lower_bound + upper_bound) / 2 # Ensure we're not returning entry price for non-zero targets if abs(result - entry_price) < (point * 5) and abs(target) > 0.01: if search_higher: result = entry_price + (100 * point) else: result = entry_price - (100 * point) return round(result, digits)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ariadng/metatrader-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server