mql5/Custom-Logic-Trading-Mini/Custom Logic For Trading Mini.mq4
Jetaroon Sriboonruang c17d37b7d7 Add Custom Logic Trading Mini source framework
Publish the preserved MT4/MT5 rolling signal-history framework with documentation, license, changelog, and flow image.
2026-09-04 19:58:50 +00:00

370 lines
14 KiB
MQL4

//+------------------------------------------------------------------+
//| Custom Logic For Trading Mini.mq4 |
//| Jollie Roger |
//| SPDX-License-Identifier: MIT |
//+------------------------------------------------------------------+
#property copyright "Jollie Roger"
#property link "https://www.mql5.com/en/market/product/119607"
#property version "3.00"
#property description "Automated trading script designed to execute trades based on custom indicator signals."
#property strict
// Define the enum for Signal Types
enum SignalType
{
STCrossOverPrice, // Cross over price
STCrossUnderPrice, // Cross under price
STCrossOverLevel, // Cross over level
STCrossUnderLevel, // Cross under level
STSymbol // Symbol/arrow
};
// Define the enum for Logic Direction
enum LogicDirection
{
DirectLogic, // Direct
ReversalLogic // Reversal
};
// Define the enum for Trading Side
enum TradingSide
{
LongSideOnly, // Long
ShortSideOnly, // Short
BothSides // Both
};
// Input parameters
input string indicator_setting = "=== Indicator Setting ===";// Indicator Setting
input string indicator_name = ""; // Indicator name
input int buy_stream_index = 0; // Buy stream index
input double buy_level = 0; // Buy level
input SignalType buy_signal = STCrossUnderPrice; // Buy signal
input int sell_stream_index = 0; // Sell stream index
input double sell_level = 0; // Sell level
input SignalType sell_signal = STCrossOverPrice; // Sell signal
input string position_sizing = "=== Position Sizing ===";// Position Sizing
input double lots_value = 0.01; // Position size
input double take_profit = 0; // Take Profit in points
input double stop_loss = 0; // Stop Loss in points
input int slippage_points = 3; // Slippage, points
input int magic_number = 42; // Magic number
input string trade_comment = ""; // Comment for orders
input string trading_parameters = "=== Trading Parameters ==="; // Trading Parameters
input bool close_on_opposite = true; // Close on opposite signal
input LogicDirection logic_direction = DirectLogic; // Logic direction
input TradingSide trading_side = BothSides; // Trading side
input int shift = 0; // Shift
input int maximum_order = 0; // Maximum order allowed (0 = not used)
input string breakeven_feature = "=== Breakeven ===";// Breakeven feature
input bool use_break_even = false; // Use break even feature
input double break_even_trigger = 0; // Break even trigger in points
input double break_even_target = 0; // Break even target in points
// Variables to track last signals and trade flags
bool prev_buy_signal = false; // Previous state of buy signal
bool prev_sell_signal = false; // Previous state of sell signal
bool initial_buy_signal_ignored = false; // Flag to ignore the first buy signal
bool initial_sell_signal_ignored = false; // Flag to ignore the first sell signal
bool ready_to_buy = false;
bool ready_to_sell = false;
int max_position = 1;
// Arrays to store recent history of long and short signals
bool long_signal_history[];
bool short_signal_history[];
// Maximum size of signal history arrays
int max_history_size = 1000;
// Function to get signal from the indicator
double GetSignal(string symbol, ENUM_TIMEFRAMES tf, int period, int stream)
{
return iCustom(symbol, tf, indicator_name, stream, period);
}
// Function to check long condition
bool IsLongCondition(int period, bool &signalAvailable)
{
double value = GetSignal(Symbol(), PERIOD_CURRENT, period, buy_stream_index);
signalAvailable = (value != EMPTY_VALUE);
if(!signalAvailable)
return false;
bool conditionMet = false; // Initialize conditionMet to false
switch(buy_signal)
{
case STCrossOverPrice:
conditionMet = value > iClose(Symbol(), PERIOD_CURRENT, period);
break;
case STCrossUnderPrice:
conditionMet = value < iClose(Symbol(), PERIOD_CURRENT, period);
break;
case STCrossOverLevel:
conditionMet = value > buy_level;
break;
case STCrossUnderLevel:
conditionMet = value < buy_level;
break;
case STSymbol:
conditionMet = value != 0 && value != EMPTY_VALUE;
break;
}
return logic_direction == DirectLogic ? conditionMet : !conditionMet;
}
// Function to check short condition
bool IsShortCondition(int period, bool &signalAvailable)
{
double value = GetSignal(Symbol(), PERIOD_CURRENT, period, sell_stream_index);
signalAvailable = (value != EMPTY_VALUE);
if(!signalAvailable)
return false;
bool conditionMet = false; // Initialize conditionMet to false
switch(sell_signal)
{
case STCrossOverPrice:
conditionMet = value > iClose(Symbol(), PERIOD_CURRENT, period);
break;
case STCrossUnderPrice:
conditionMet = value < iClose(Symbol(), PERIOD_CURRENT, period);
break;
case STCrossOverLevel:
conditionMet = value > sell_level;
break;
case STCrossUnderLevel:
conditionMet = value < sell_level;
break;
case STSymbol:
conditionMet = value != 0 && value != EMPTY_VALUE;
break;
}
return logic_direction == DirectLogic ? conditionMet : !conditionMet;
}
// Function to get the total number of positions for the current symbol and magic number
int positionTotal()
{
int count = 0;
int totalOrders = OrdersTotal();
for(int i = 0; i < totalOrders; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number)
{
count++;
}
}
}
return count;
}
// Function to close positions of a certain type
void ClosePosition(int type)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderType() == type && OrderMagicNumber() == magic_number)
{
if(!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage_points, clrNONE))
{
Print("Error closing position: ", GetLastError());
}
}
}
}
}
// Execution trade
void ExecutionTrade()
{
if(shift < 0 || shift >= Bars)
return;
int currentPeriod = iBarShift(Symbol(), PERIOD_CURRENT, Time[shift]);
if(currentPeriod < 0)
return;
bool longSignalAvailable = false;
bool shortSignalAvailable = false;
bool longCondition = IsLongCondition(currentPeriod, longSignalAvailable);
bool shortCondition = IsShortCondition(currentPeriod, shortSignalAvailable);
// Check for opposite signals and close positions if needed
if(close_on_opposite)
{
if(shortSignalAvailable && (trading_side == LongSideOnly || trading_side == BothSides) && shortCondition)
{
ClosePosition(OP_BUY);
}
if(longSignalAvailable && (trading_side == ShortSideOnly || trading_side == BothSides) && longCondition)
{
ClosePosition(OP_SELL);
}
}
bool isAvailableQuota = (maximum_order - positionTotal() > 0 || maximum_order == 0);
// Update long signal history array only after a valid indicator read.
if(longSignalAvailable)
{
if(ArraySize(long_signal_history) >= max_history_size)
{
for(int i = 1; i < ArraySize(long_signal_history); i++)
long_signal_history[i - 1] = long_signal_history[i];
ArrayResize(long_signal_history, ArraySize(long_signal_history) - 1);
}
ArrayResize(long_signal_history, ArraySize(long_signal_history) + 1);
long_signal_history[ArraySize(long_signal_history) - 1] = longCondition;
}
// Update short signal history array only after a valid indicator read.
if(shortSignalAvailable)
{
if(ArraySize(short_signal_history) >= max_history_size)
{
for(int i = 1; i < ArraySize(short_signal_history); i++)
short_signal_history[i - 1] = short_signal_history[i];
ArrayResize(short_signal_history, ArraySize(short_signal_history) - 1);
}
ArrayResize(short_signal_history, ArraySize(short_signal_history) + 1);
short_signal_history[ArraySize(short_signal_history) - 1] = shortCondition;
}
// Check if the current long signal is valid (changed from false to true)
if(longSignalAvailable && ArraySize(long_signal_history) >= 2 && long_signal_history[ArraySize(long_signal_history) - 1] && !long_signal_history[ArraySize(long_signal_history) - 2])
{
// If the current long signal is valid, open a long position
if((trading_side == LongSideOnly || trading_side == BothSides) && longCondition && isAvailableQuota)
{
Print("Valid Long Signal Detected"); // Debug print for valid long signal
// Calculate TP and SL prices for buy order
double tpPrice = take_profit > 0 ? Ask + take_profit * Point : 0;
double slPrice = stop_loss > 0 ? Ask - stop_loss * Point : 0;
// Open a new buy position
int ticket = OrderSend(Symbol(), OP_BUY, lots_value, Ask, slippage_points, slPrice, tpPrice, trade_comment, magic_number, 0, Blue);
if(ticket < 0)
Print("Error opening buy order: ", GetLastError());
}
}
// Check if the current short signal is valid (changed from false to true)
if(shortSignalAvailable && ArraySize(short_signal_history) >= 2 && short_signal_history[ArraySize(short_signal_history) - 1] && !short_signal_history[ArraySize(short_signal_history) - 2])
{
// If the current short signal is valid, open a short position
if((trading_side == ShortSideOnly || trading_side == BothSides) && shortCondition && isAvailableQuota)
{
Print("Valid Short Signal Detected"); // Debug print for valid short signal
// Calculate TP and SL prices for sell order
double tpPrice = take_profit > 0 ? Bid - take_profit * Point : 0;
double slPrice = stop_loss > 0 ? Bid + stop_loss * Point : 0;
// Open a new sell position
int ticket = OrderSend(Symbol(), OP_SELL, lots_value, Bid, slippage_points, slPrice, tpPrice, trade_comment, magic_number, 0, Red);
if(ticket < 0)
Print("Error opening sell order: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CheckBreakEven()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number)
{
// Calculate the break-even level
double breakEvenLevel;
if(OrderType() == OP_BUY)
{
breakEvenLevel = OrderOpenPrice() + break_even_target * Point;
// Check if the price has reached the trigger point
if(Bid - OrderOpenPrice() >= break_even_trigger * Point && (OrderStopLoss() < OrderOpenPrice() || OrderStopLoss() == 0))
{
// Modify the stop loss to the break-even level
if(!OrderModify(OrderTicket(), OrderOpenPrice(), breakEvenLevel, OrderTakeProfit(), 0, clrNONE))
{
Print("Error modifying buy order for break-even: ", GetLastError());
}
}
}
else
if(OrderType() == OP_SELL)
{
breakEvenLevel = OrderOpenPrice() - break_even_target * Point;
// Check if the price has reached the trigger point
if(OrderOpenPrice() - Ask >= break_even_trigger * Point && (OrderStopLoss() > OrderOpenPrice() || OrderStopLoss() == 0))
{
// Modify the stop loss to the break-even level
if(!OrderModify(OrderTicket(), OrderOpenPrice(), breakEvenLevel, OrderTakeProfit(), 0, clrNONE))
{
Print("Error modifying sell order for break-even: ", GetLastError());
}
}
}
}
}
}
}
// OnTick function to handle trading logic
void OnTick()
{
ExecutionTrade();
// Check for break-even conditions
if(use_break_even)
CheckBreakEven();
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(indicator_name == "")
{
Print("Initialization failed: indicator_name is empty.");
return(INIT_PARAMETERS_INCORRECT);
}
if(lots_value <= 0 || shift < 0 || maximum_order < 0 || slippage_points < 0 ||
buy_stream_index < 0 || sell_stream_index < 0 || take_profit < 0 ||
stop_loss < 0 || break_even_target < 0)
{
Print("Initialization failed: one or more numeric inputs are outside their valid range.");
return(INIT_PARAMETERS_INCORRECT);
}
if(use_break_even && break_even_trigger <= 0)
{
Print("Initialization failed: break_even_trigger must be greater than zero when break-even is enabled.");
return(INIT_PARAMETERS_INCORRECT);
}
initial_buy_signal_ignored = false; // Reset the flag for buy signal
initial_sell_signal_ignored = false; // Reset the flag for sell signal
ArrayResize(long_signal_history, 0); // Initialize the long signal history array
ArrayResize(short_signal_history, 0); // Initialize the short signal history array
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ArrayResize(long_signal_history, 0); // Clear the long signal history array
ArrayResize(short_signal_history, 0); // Clear the short signal history array
Print("EA deinitialized");
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+