222 lines
13 KiB
Plaintext
222 lines
13 KiB
Plaintext
// ★★★ EA_SingleLogic_LongOnly ★★★
|
|
//---------------------------------------------
|
|
// (1) Input parameters
|
|
//---------------------------------------------
|
|
// --- Parameters for Magic_A
|
|
input double SARStep = 0.001; // SAR acceleration factor increment
|
|
input double SARMaxStep = 0.2; // Maximum SAR acceleration factor
|
|
input double TPPips = 90; // Take Profit in pips
|
|
input double SLPips = 70; // Stop Loss in pips
|
|
// --- Other settings
|
|
input double MaxSpreadPips = 3.0; // Maximum allowed spread (pips)
|
|
input int SlippagePips = 3; // Allowed slippage (pips)
|
|
input double LotSize = 0.1; // Fixed lot size
|
|
input int MaxOpenBuyPositions = 1; // Maximum number of open BUY positions
|
|
|
|
//---------------------------------------------
|
|
// (2) Magic number
|
|
//---------------------------------------------
|
|
input int Magic_A = 12345;
|
|
|
|
//---------------------------------------------
|
|
// (3) Internal state variables
|
|
//---------------------------------------------
|
|
datetime prevTime_A = 0;
|
|
|
|
//---------------------------------------------
|
|
// (4) ENUM: Exit / Entry signals
|
|
//---------------------------------------------
|
|
enum SignalType
|
|
{
|
|
NO_SIGNAL = 0,
|
|
BUY_ENTRY,
|
|
BUY_EXIT
|
|
};
|
|
|
|
//---------------------------------------------
|
|
// (6) New bar detection
|
|
//---------------------------------------------
|
|
bool IsNewBar(int timeframe, datetime &lastBarTime)
|
|
{
|
|
datetime currentBar = iTime(Symbol(), timeframe, 0);
|
|
if (currentBar != lastBarTime)
|
|
{
|
|
lastBarTime = currentBar;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (7) Pip size calculation
|
|
//---------------------------------------------
|
|
double Pip()
|
|
{
|
|
return (Digits == 5 || Digits == 3) ? Point * 10 : Point;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// Convert pips to points (for slippage)
|
|
int PipToPoint(double pips)
|
|
{
|
|
return (int)MathRound(pips * Pip() / Point);
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (11) Count open BUY orders for this EA
|
|
//---------------------------------------------
|
|
int CountOrdersByTypeThisEA(int type)
|
|
{
|
|
int count = 0;
|
|
for (int i = OrdersTotal() - 1; i >= 0; i--)
|
|
{
|
|
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
|
{
|
|
if (OrderSymbol() == Symbol() &&
|
|
OrderMagicNumber() == Magic_A &&
|
|
OrderType() == type)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (12) Check if a new BUY order can be placed
|
|
//---------------------------------------------
|
|
bool CanPlaceNewBuy()
|
|
{
|
|
return CountOrdersByTypeThisEA(OP_BUY) < MaxOpenBuyPositions;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (14) Exit signal logic
|
|
//---------------------------------------------
|
|
SignalType ExitSignalA()
|
|
{
|
|
double SAR0 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 0);
|
|
double SAR1 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 1);
|
|
double SAR2 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 2);
|
|
|
|
if ((Low[1] > SAR1 && Close[0] <= SAR0) ||
|
|
(High[2] < SAR2 && High[1] < SAR1 && High[0] < SAR0))
|
|
return BUY_EXIT;
|
|
|
|
return NO_SIGNAL;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (15) Entry signal logic
|
|
//---------------------------------------------
|
|
SignalType EntrySignalA()
|
|
{
|
|
double SAR1 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 1);
|
|
double SAR2 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 2);
|
|
double SAR3 = iSAR(_Symbol, 0, SARStep, SARMaxStep, 3);
|
|
|
|
if ((High[2] < SAR2 && Close[1] >= SAR1) ||
|
|
(Low[3] > SAR3 && Low[2] > SAR2 && Low[1] > SAR1))
|
|
return BUY_ENTRY;
|
|
|
|
return NO_SIGNAL;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (21) Exit processing (BUY only)
|
|
//---------------------------------------------
|
|
void HandleExitA(SignalType sig)
|
|
{
|
|
if (sig != BUY_EXIT) return;
|
|
|
|
double closePrice = Bid;
|
|
|
|
for (int i = OrdersTotal() - 1; i >= 0; i--)
|
|
{
|
|
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
|
{
|
|
if (OrderMagicNumber() == Magic_A &&
|
|
OrderSymbol() == _Symbol &&
|
|
OrderType() == OP_BUY)
|
|
{
|
|
int ticket = OrderTicket();
|
|
double lots = OrderLots();
|
|
|
|
bool result = OrderClose(
|
|
ticket,
|
|
lots,
|
|
closePrice,
|
|
PipToPoint(SlippagePips),
|
|
clrOrange
|
|
);
|
|
|
|
if (!result)
|
|
PrintFormat("❌ OrderClose failed. Ticket=%d Error=%d", ticket, GetLastError());
|
|
else
|
|
PrintFormat("✅ Order closed successfully. Ticket=%d", ticket);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (22) Entry processing (BUY only)
|
|
//---------------------------------------------
|
|
void HandleEntryA(SignalType sig)
|
|
{
|
|
if (sig != BUY_ENTRY) return;
|
|
|
|
// Spread check
|
|
double spreadPips = (Ask - Bid) / Pip();
|
|
if (spreadPips > MaxSpreadPips)
|
|
{
|
|
PrintFormat("❌ Spread too high (%.1f pips). Entry skipped.", spreadPips);
|
|
return;
|
|
}
|
|
|
|
if (!CanPlaceNewBuy()) return;
|
|
|
|
double price = Ask;
|
|
double sl = NormalizeDouble(price - SLPips * Pip(), Digits);
|
|
double tp = NormalizeDouble(price + TPPips * Pip(), Digits);
|
|
int slippagePoints = PipToPoint(SlippagePips);
|
|
|
|
int ticket = OrderSend(
|
|
_Symbol,
|
|
OP_BUY,
|
|
LotSize,
|
|
price,
|
|
slippagePoints,
|
|
sl,
|
|
tp,
|
|
"Magic_A Entry",
|
|
Magic_A,
|
|
0,
|
|
clrOrange
|
|
);
|
|
|
|
if (ticket > 0)
|
|
PrintFormat("✅ Magic_A BUY order placed. Ticket=%d", ticket);
|
|
else
|
|
PrintFormat("❌ Magic_A OrderSend failed. Error=%d", GetLastError());
|
|
}
|
|
|
|
//---------------------------------------------
|
|
// (27) Main OnTick processing
|
|
//---------------------------------------------
|
|
void OnTick()
|
|
{
|
|
// EXIT: evaluated on every tick and executed immediately if conditions are met
|
|
SignalType exitSig = ExitSignalA();
|
|
HandleExitA(exitSig);
|
|
|
|
// ENTRY: evaluated only on a new bar
|
|
if (IsNewBar(PERIOD_CURRENT, prevTime_A))
|
|
{
|
|
SignalType entrySig = EntrySignalA();
|
|
HandleEntryA(entrySig);
|
|
}
|
|
}
|
|
|
|
// --- END --- |