The trading strategy “Head or Tail” belongs to the category of high-risk short-term trading approaches used mainly on the stock market and Forex. Its name is due to the randomness of decision-making, similar to flipping a coin (“heads” — buy an asset, “tails” — sell). This strategy is based solely on intuitive decisions or random signals and ignores fundamental factors of market analysis.
The source code of the trading strategy has been added to the base codes:
MetaTrader 5: https://www.mql5.com/en/code/11637
#property copyright "Copyright 2025, Trading-Go." // Setting copyright property #property link "https://www.mql5.com/en/channels/tradingo-go-en" // Setting developer resource link #property version "26.010" // Program version
The provided code consists of compiler directives for a program written as an Expert Advisor (EA) or indicator in the MetaTrader platform using the MQL4/MQL5 language.
Let's break down each line separately:
1. Copyright Property:
#property copyright "Copyright 2025, Trading-Go."
This directive sets legal ownership rights over the EA's or indicator’s source code. It specifies the owner of intellectual property rights and helps mark the product's affiliation with a specific organization or individual ("Trading-Go"). This information appears in the properties window of the EA/indicator within the client terminal.
2. Developer Resource Link:
#property link " "
This directive allows setting a web link to the developer's resources. When traders use this EA or indicator, this link becomes accessible via its properties menu. It's beneficial for developers since they can direct users to support pages, documentation, or community-related content related to their products.
3. Version Specification:
#property version "26.010"
Here, the software version is defined. Typically, developers specify versions in formats like XX.XX, where the first digit represents major version numbers, second minor version updates, and third patch releases. The version assists users in tracking updates and maintaining compatibility between tools.
Thus, these two libraries simplify the development of complex automated trading algorithms, allowing focus directly on strategy logic rather than low-level interactions with broker servers.
input double iLots = 0.10; // Input parameter for lot size (trade volume) input int iTakeProfit = 450; // Input parameter for profit fixing level (Take Profit) input int iStopLoss = 390; // Input parameter for loss limitation level (Stop Loss) input int iMagicNumber = 227; // Input parameter for unique deal number (Magic Number) input int iSlippage = 30; // Input parameter for maximum price slippage string sy = ""; // Variable to store instrument symbol double pt = 0; // Variable for point calculation step int dt = 0; // Variable for decimal places count
Let us examine each element of the given block of code individually, explaining its purpose and role in configuring an automatic expert advisor (Expert Advisor) in the MetaTrader trading platform.
Input Parameters:
1. Lot Size (iLots = 0.10):
iLots = 0.10;
This input parameter defines the lot size (volume of trade). The default value is set at 0.10. The lot size determines how many assets will be bought or sold per transaction. For example, if the instrument is EURUSD, then a lot size of 0.1 corresponds to 10 thousand units of the base currency (such as euros).
2. Take Profit Level (iTakeProfit = 450):
iTakeProfit = 450;
This integer parameter specifies the profit-fixation level (Take Profit). The default value equals 450. Take Profit automatically closes a position when the market reaches the indicated profit level relative to the entry price. The level is expressed in pips.
3. Stop Loss Level (iStopLoss = 390):
iStopLoss = 390;
This integer parameter establishes the loss-limitation level (Stop Loss). By default, it's set at 390. Stop Loss automatically closes a position if the market moves against your position and losses reach the predefined threshold. Losses are fixed in pips.
4. Unique Deal Number (iMagicNumber = 227):
iMagicNumber = 227;
This integer parameter serves as a unique identification number (Magic Number) for transactions. Each event (position opening, closing, etc.) receives a unique Magic Number that filters deals associated with this particular EA. The default value is 227.
5. Maximum Price Deviation Points (iSlippage = 30):
iSlippage = 30;
This integer parameter restricts the maximum deviation in price during order execution from the requested price. A default value of 30 pips ensures that if the actual price deviates more than the specified amount, the trade won’t execute. This protects against excessive slippage.
Local Variables:
1. Instrument Symbol Storage (sy = ""):
sy = "";
A variable of type string stores the financial instrument symbol (e.g., "EURUSD") being traded. Initially empty ("").
2. Point Calculation Step (pt = 0):
pt = 0;
A variable of type double holds the size of the smallest price change increment for the instrument. Used for calculating Take Profit and Stop Loss values based on pip counts. Defaulted to zero (0).
3. Decimal Places Count (dt = 0):
dt = 0;
An integer variable intended to track the number of decimal places after the decimal point in quotes for the chosen instrument. Knowing the number of decimals is crucial for accurate calculations of profits, stops, and other metrics. Initialized to zero (0).
This block of code is designed to establish initial configurations and prepare the environment for an automated expert advisor in MetaTrader. The input parameters allow flexible configuration before starting trading sessions.
sy = _Symbol; // Getting current trading instrument pt = _Point; // Getting minimum unit change size dt = _Digits; // Getting number of decimal digits in price trade.SetExpertMagicNumber(iMagicNumber); // Setting unique deal number for trade operations trade.SetDeviationInPoints(iSlippage); // Setting maximum price deviation points trade.SetTypeFillingBySymbol(sy); // Setting order execution type according to instrument settings trade.SetMarginMode(); // Setting margin mode
Each statement plays a critical role in preparing conditions for successful EA operation. Let's explore them further:
Environmental Variables:
1. Current Trading Instrument Retrieval:
sy = _Symbol;
This assigns the global variable sy the name of the currently traded instrument retrieved from the built-in constant _Symbol. Thus, we obtain access to the instrument necessary for subsequent calculations and interaction.
2. Minimum Unit Change Size:
pt = _Point;
Sets the variable pt to the minimal change in price increments (_Point). This basic unit measures changes in pricing needed for proper interpretation of system signals and adjustment of orders.
3. Decimal Digits Count:
dt = _Digits;
Assigns the variable dt representing the number of decimal places in the price quote of the current instrument. Since different instruments have varying precision (e.g., USDJPY uses two decimal places while EURUSD uses four), knowing this detail is essential for correct rounding and computations.
Trade Configuration:
4. Unique Deal Number Setup:
trade.SetExpertMagicNumber(iMagicNumber);
Establishes a unique magic number (Magic Number) for all transactions initiated by this EA. The magic number identifies deals made specifically by this EA and simplifies filtering by this criterion. Uniqueness guarantees no confusion among various robot strategies.
5. Maximum Price Deviation:
trade.SetDeviationInPoints(iSlippage);
Defines the acceptable maximum deviation in price execution compared to the expected price. Ensures protection against significant market fluctuations. Lower tolerance means higher accuracy in executing requests.
6. Order Execution Type:
trade.SetTypeFillingBySymbol(sy);
Configures the method of filling orders depending on the characteristics of the instrument itself. Some instruments require instant execution ("Market Execution"), whereas others may accept delayed executions ("Instant Execution"). This command automatically selects the appropriate mode based on the instrument's specifications.
7. Margin Mode Adjustment:
trade.SetMarginMode();
Adjusts the margin requirements for trading. Different methods of managing collateral vary across instruments and trading modes. Correct setup affects the free capital needed to maintain positions and minimizes risks of forced closure due to insufficient funds.
These steps ensure optimal preparation for efficient functioning of the EA in the MetaTrader platform.
double stepvol = SymbolInfoDouble(sy, SYMBOL_VOLUME_STEP); // Get the lot size change step for the selected symbol if(stepvol > 0.0) // If the lot size step is positive, apply calculation of adjusted lot size lt = stepvol * (MathFloor(iLots / stepvol) - 1); // Round down the lot size to the nearest step value and decrease by one step //--- double minvol = SymbolInfoDouble(sy, SYMBOL_VOLUME_MIN); // Get minimum allowed lot size for the specified symbol if(lt < minvol) // If the adjusted lot size is less than the minimum possible value, reset it to zero lt = 0.0; ::MathSrand(GetTickCount()); // Generating initial number for random generator
Let’s walk through each step sequentially:
Step 1: Retrieve Volume Step Information:
double stepvol = SymbolInfoDouble(sy, SYMBOL_VOLUME_STEP);
This retrieves the minimum step change in lot sizes for the selected instrument. For instance, some instruments might have a step of 0.01 lots, meaning you cannot trade fractional amounts smaller than that.
Step 2: Verify Positive Step Value:
if(stepvol > 0.0)
Checks whether the step value is greater than zero. Negative or zero steps would render adjustments meaningless.
Step 3: Calculate Adjusted Lot Size:
lt = stepvol * (MathFloor(iLots / stepvol) - 1);
Reduces the user-defined lot size (iLots) by subtracting one full step. Here's what happens internally:
- Divide the desired lot size by the step (iLots / stepvol).
- Round down the result using MathFloor().
- Subtract one step from the rounded-down value.
- Multiply back by the step to get the final reduced lot size.
Step 4: Fetch Minimum Allowed Lot Size:
double minvol = SymbolInfoDouble(sy, SYMBOL_VOLUME_MIN);
Retrieves the minimum permitted lot size for the given instrument. Exchanges impose limits on the smallest tradable volumes.
Step 5: Reset Below Minimal Values:
if(lt < minvol)
lt = 0.0;
If the calculated lot size falls below the exchange-imposed minimum, the lot size is reset to zero, preventing invalid orders.
Step 6: Initialize Random Generator Seed:
::MathSrand(GetTickCount());
Seeds the random number generator with the current tick count, ensuring unpredictability in future randomized processes.
Overall Purpose:
This block dynamically adjusts lot sizes according to exchange regulations, avoiding errors during position openings and enhancing trade safety.
int total = ::PositionsTotal(), b = 0, s = 0; // Total open positions and purchase/sale counters double Bid = ::SymbolInfoDouble(sy, SYMBOL_BID); // Current bid price (selling price) double Ask = ::SymbolInfoDouble(sy, SYMBOL_ASK); // Current ask price (buying price) double new_sl = 0, new_tp = 0, old_sl = 0, old_tp = 0; // New and old stop loss and take profit levels if(Bid <= 0 || Ask <= 0) // If prices are incorrect return; // Exit function
We’ll analyze each part of this preparatory block:
Initializing Variables:
1. Open Position Counter:
total = ::PositionsTotal();
Retrieves the total number of open positions across all symbols and types. Useful for later position management and optimization.
2. Purchase/Sale Counters:
b = 0, s = 0;
Counters initialized to track the number of opened buy (b) and sell (s) positions respectively. They start at zero but increase as we iterate through existing positions.
Current Market Prices:
3. BID Price Acquisition:
Bid = ::SymbolInfoDouble(sy, SYMBOL_BID);
Fetches the best available selling price (bid) for the current instrument. Necessary for evaluating stop-loss and take-profit levels.
4. ASK Price Acquisition:
Ask = ::SymbolInfoDouble(sy, SYMBOL_ASK);
Obtains the best buying price (ask) for the same instrument. Both bid and ask are essential for computing realistic profit targets and risk management thresholds.
Preparing Stop-Loss/Take-Profit Levels:
5. New/Old Stop-Loss and Take-Profit Definitions:
new_sl = 0, new_tp = 0, old_sl = 0, old_tp = 0;
Declares variables to hold both previous and newly computed stop-loss (SL) and take-profit (TP) levels. These are initially set to zero until further processing occurs.
Error Handling:
6. Invalid Price Protection:
if(Bid <= 0 || Ask <= 0)
return;
Ensures that only valid bid and ask prices are processed. If either is missing or negative, the script exits immediately to prevent faulty actions.
With these preparations complete, subsequent blocks proceed to calculate precise levels for stop-losses and take-profits, thereby improving overall trading efficiency.
for(int i = 0; i < total; i++) // Loop through open positions if(posit.SelectByIndex(i)) // Select position by index if(posit.Symbol() == sy) // Check instrument of position if(posit.Magic() == iMagicNumber) // Check unique number of position { old_sl = ::NormalizeDouble(posit.StopLoss(), dt); // Normalizing old stop loss to match decimal places old_tp = ::NormalizeDouble(posit.TakeProfit(), dt); // Normalizing old take profit to match decimal places if(posit.PositionType() == POSITION_TYPE_BUY) // If position is BUY (purchase) { new_sl = ::NormalizeDouble(Ask - iStopLoss * pt, dt); // Calculating new stop loss below current ask price new_tp = ::NormalizeDouble(Ask + iTakeProfit * pt, dt); // Calculating new take profit above current ask price b++; // Incrementing purchase counter } if(posit.PositionType() == POSITION_TYPE_SELL) // If position is SELL (sale) { new_sl = ::NormalizeDouble(Bid + iStopLoss * pt, dt); // Calculating new stop loss above current bid price new_tp = ::NormalizeDouble(Bid - iTakeProfit * pt, dt); // Calculating new take profit below current bid price s++; // Incrementing sale counter } if(old_sl == 0 || old_tp == 0) // If new levels differ from old ones trade.PositionModify(posit.Ticket(), new_sl, new_tp);// Modifying position with updated SL and TP }
Explanation:
Iteration Through Open Positions:
1. Selection by Index:
if(posit.SelectByIndex(i))
Selects a position based on its index in the list of open positions. After selection, the position object becomes accessible for modification.
Instrument Matching:
2. Checking Instrument Consistency:
if(posit.Symbol() == sy && posit.Magic() == iMagicNumber)
Verifies that the position belongs to the relevant instrument (symbol matches 'sy') and has the matching magic number ('iMagicNumber'). Both checks ensure precise targeting of the right position.
Updating Stop-Loss and Take-Profit Levels:
3. Retrieving Old Levels:
old_sl = NormalizeDouble(posit.StopLoss(), dt);
old_tp = NormalizeDouble(posit.TakeProfit(), dt);
Normalizes previously stored stop-loss and take-profit levels to match the instrument’s decimal format, ensuring consistency in floating-point representations.
4. Updating Long Positions:
if(posit.PositionType() == POSITION_TYPE_BUY)
For buy positions, calculates new stop-loss below the current ask price and new take-profit above the ask price, adjusting for the configured stop-loss/take-profit offsets.
5. Updating Short Positions:
if(posit.PositionType() == POSITION_TYPE_SELL)
Similarly handles short positions, placing stop-loss above the bid price and take-profit below the bid price.
6. Applying Changes:
if(old_sl == 0 || old_tp == 0)
trade.PositionModify(posit.Ticket(), new_sl, new_tp);
Updates the position with new stop-loss and take-profit levels if any were changed. Only modified positions undergo updating.
Conclusion:
This loop efficiently manages multiple open positions, updating protective measures such as stop-loss and take-profit to enhance profitability and reduce risk exposure.
if((b + s) == 0) // If there are no active positions if(::MathRand() % 2 == 0) // Randomly selecting position direction { if(trade.CheckVolume(sy, lt, Ask, ORDER_TYPE_BUY)) // Verifying sufficient funds for the required trading action if(trade.Buy(lt)) // Opening a long position (BUY) return; // Terminate function execution } else if(trade.CheckVolume(sy, lt, Bid, ORDER_TYPE_SELL)) // Verifying sufficient funds for the required trading action if(trade.Sell(lt)) // Opening a short position (SELL) return; // Terminate function execution
Description:
When No Active Position Exists:
1. Condition Evaluation:
if((b + s) == 0)
Checks if there are no active positions (both buy and sell counters equal zero). If true, proceeds to randomly select a position direction.
Random Direction Selection:
2. Using Random Function:
if(::MathRand() % 2 == 0)
Utilizes the modulo operator (% 2) to randomly decide between opening a buy or sell position. If the remainder is zero, a buy position is considered; otherwise, a sell position is attempted.
Buy Position Creation:
3. Fund Availability Check:
if(trade.CheckVolume(sy, lt, Ask, ORDER_TYPE_BUY))
Before initiating a buy position, verifies sufficient account balance to cover the proposed trade volume (lt) at the current asking price (Ask).
4. Opening Buy Position:
if(trade.Buy(lt))
Attempts to create a buy position using the specified lot size (lt). Upon success, terminates further execution of the function.
Sell Position Creation:
5. Alternative Scenario:
else
if(trade.CheckVolume(sy, lt, Bid, ORDER_TYPE_SELL))
In case the random selector chose a sell position, repeats the fund availability check but now for selling at the bid price (Bid).
6. Initiating Sale:
if(trade.Sell(lt))
Opens a sell position if funding permits, again halting further execution upon completion.
Final Outcome:
This block implements a simple yet effective mechanism for creating random buy or sell positions whenever none exist, emphasizing frequency of trades over deliberate strategic planning.
void OnDeinit(const int reason) // Deinitialization function { }
While the deinitialization block remains blank here, it's useful even without immediate functionality. An empty block acts as a placeholder reminding developers about potential cleanup tasks. Future expansions could include cleaning up resources, closing windows, or ending network connections.
Summary:
Overall, the code demonstrates how to configure an Expert Advisor in MetaTrader effectively, handling dynamic lot adjustments, position modifications, and safeguards against erroneous inputs or market anomalies.


