780 lines
No EOL
54 KiB
MQL5
780 lines
No EOL
54 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| QuarterTheory_OPTIMIZED.mq5 |
|
|
//| OPTIMIZED: Wide SL + Strong MA TPs + Liquidity Sweeps |
|
|
//| Stronger MAs (230+) are Major Triggers & TPs - Stay in Longer |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Optimized System - Hit TPs, Re-enter Sweeps"
|
|
#property version "9.00"
|
|
#property strict
|
|
|
|
#include <Trade/Trade.mqh>
|
|
CTrade Trade;
|
|
|
|
//================ INPUT PARAMETERS ==================//
|
|
input group "=== GENERAL ==="
|
|
input int MagicNumber = 456789;
|
|
input double Risk_Per_Trade = 1.5;
|
|
input int Max_Simultaneous_Trades = 6;
|
|
|
|
input group "=== RISK MANAGEMENT (WIDER SL) ==="
|
|
input int Initial_SL_Points = 300; // WIDER! 30 pips for Gold
|
|
input int BreakEven_Points = 100; // Later BE
|
|
input bool Use_Wider_SL_On_Strong = true; // Even wider on 3+ MA alignment
|
|
input int Strong_Signal_SL_Points = 450; // 45 pips when 3+ MAs
|
|
|
|
input group "=== MOVING AVERAGES ==="
|
|
input int MA_1 = 7; // Fast - Entry signal
|
|
input int MA_2 = 14; // Fast - Entry signal
|
|
input int MA_3 = 21; // Fast - Entry signal
|
|
input int MA_4 = 50; // Medium - Entry signal
|
|
input int MA_5 = 140; // Medium - Entry signal
|
|
input int MA_6 = 230; // STRONG - Major trigger/TP
|
|
input int MA_7 = 500; // STRONG - Major TP
|
|
input int MA_8 = 1000; // STRONG - Major TP
|
|
input int MA_9 = 1100; // STRONG - Major TP
|
|
input int MA_10 = 1300; // STRONG - Final TP
|
|
|
|
input group "=== MA STRENGTH RULES ==="
|
|
input bool Strong_MAs_Are_Magnets = true; // 230+ are powerful TPs
|
|
input int MA_Touch_Buffer_Points = 20; // Buffer for MA "kiss"
|
|
input int Min_Aligned_For_Entry = 3; // Min MAs aligned
|
|
input int Strong_Aligned_Count = 5; // 5+ = very strong
|
|
input bool Stay_In_On_Strong = true; // Hold longer if 5+ aligned
|
|
|
|
input group "=== LIQUIDITY SWEEP RE-ENTRY ==="
|
|
input bool Trade_Liquidity_Sweeps = true; // Re-enter after SL hit
|
|
input int Sweep_Detection_Points = 50; // How far past level = sweep
|
|
input int Sweep_Cooldown_Bars = 3; // Wait 3 bars after sweep
|
|
input bool Only_Sweep_At_Fib = true; // Only sweep at Fib levels
|
|
|
|
input group "=== DYNAMIC TAKE PROFIT ==="
|
|
// WEAK (3 MAs aligned)
|
|
input double Weak_Close_At_MA6 = 20.0; // Close 20% at MA 230
|
|
input double Weak_Close_At_MA7 = 30.0; // Close 30% at MA 500
|
|
input double Weak_Close_At_MA8 = 30.0; // Close 30% at MA 1000
|
|
// MEDIUM (4 MAs aligned)
|
|
input double Medium_Close_At_MA6 = 15.0; // Close 15% at MA 230
|
|
input double Medium_Close_At_MA7 = 25.0; // Close 25% at MA 500
|
|
input double Medium_Close_At_MA8 = 25.0; // Close 25% at MA 1000
|
|
// STRONG (5+ MAs aligned)
|
|
input double Strong_Close_At_MA6 = 10.0; // Close 10% at MA 230
|
|
input double Strong_Close_At_MA7 = 20.0; // Close 20% at MA 500
|
|
input double Strong_Close_At_MA8 = 25.0; // Close 25% at MA 1000
|
|
// Remaining runs to MA 1100 and 1300
|
|
|
|
input group "=== TRAILING STRATEGY ==="
|
|
input bool Trail_To_Strong_MAs = true; // Trail SL to 230+
|
|
input int Trail_Start_Points = 150; // Start trailing
|
|
input int Trail_Step_Points = 30;
|
|
input int Trail_Stop_Points = 50;
|
|
|
|
input group "=== PRICE LEVELS ==="
|
|
input int Lookback_Bars = 200;
|
|
input int Level_Buffer_Points = 40;
|
|
input bool Show_Levels = true;
|
|
|
|
input group "=== DAILY LIMITS ==="
|
|
input double Max_Daily_Loss_Percent = 4.0; // Higher tolerance
|
|
input double Max_Daily_Profit_Percent = 20.0; // Higher target
|
|
input int Max_Trades_Per_Day = 25;
|
|
|
|
//================ GLOBALS ==================//
|
|
double PriceLevels[];
|
|
string LevelTypes[];
|
|
int TotalLevels = 0;
|
|
|
|
int MA_Handles[10];
|
|
double MA_Current[10];
|
|
double MA_Previous[10];
|
|
|
|
int TRIX_Handle;
|
|
double TRIX_Current = 0;
|
|
|
|
struct Position
|
|
{
|
|
ulong ticket;
|
|
double entry;
|
|
double original_lot;
|
|
bool is_buy;
|
|
int ma_strength; // 3=weak, 4=medium, 5+=strong
|
|
double last_sl_hit; // Track liquidity sweeps
|
|
datetime sweep_time;
|
|
bool tp_ma6_hit; // MA 230
|
|
bool tp_ma7_hit; // MA 500
|
|
bool tp_ma8_hit; // MA 1000
|
|
bool tp_ma9_hit; // MA 1100
|
|
};
|
|
Position OpenPositions[];
|
|
|
|
struct SweepMemory
|
|
{
|
|
double level;
|
|
bool was_buy;
|
|
datetime time;
|
|
int bars_ago;
|
|
};
|
|
SweepMemory RecentSweeps[50];
|
|
int TotalSweeps = 0;
|
|
|
|
double DailyStart = 0;
|
|
int TodayTrades = 0;
|
|
datetime LastDay = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
Print("========================================");
|
|
Print("OPTIMIZED EA v9.0");
|
|
Print("Wide SL + Strong MA TPs + Liquidity Sweeps");
|
|
Print("========================================");
|
|
|
|
Trade.SetExpertMagicNumber(MagicNumber);
|
|
Trade.SetDeviationInPoints(50);
|
|
|
|
// Initialize MAs
|
|
int periods[10] = {MA_1, MA_2, MA_3, MA_4, MA_5, MA_6, MA_7, MA_8, MA_9, MA_10};
|
|
for(int i=0; i<10; i++)
|
|
{
|
|
MA_Handles[i] = iMA(_Symbol, PERIOD_CURRENT, periods[i], 0, MODE_EMA, PRICE_CLOSE);
|
|
if(MA_Handles[i] == INVALID_HANDLE)
|
|
{
|
|
Print("ERROR: MA ", periods[i], " failed");
|
|
return INIT_FAILED;
|
|
}
|
|
}
|
|
|
|
TRIX_Handle = iMA(_Symbol, PERIOD_CURRENT, 18, 0, MODE_EMA, PRICE_CLOSE);
|
|
|
|
CalculatePriceLevels();
|
|
if(Show_Levels) DrawLevels();
|
|
|
|
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
|
Print("Entry: ", Min_Aligned_For_Entry, "+ MAs | Strong: ", Strong_Aligned_Count, "+");
|
|
Print("SL: ", Initial_SL_Points, " pts | Strong: ", Strong_Signal_SL_Points, " pts");
|
|
Print("Strong MAs (230+) are MAJOR TPs");
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
for(int i=0; i<10; i++) IndicatorRelease(MA_Handles[i]);
|
|
IndicatorRelease(TRIX_Handle);
|
|
ObjectsDeleteAll(0, "Level_");
|
|
ObjectsDeleteAll(0, "Arrow_");
|
|
ObjectsDeleteAll(0, "Sweep_");
|
|
Print("EA Stopped");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CalculatePriceLevels()
|
|
{
|
|
ArrayResize(PriceLevels, 0);
|
|
ArrayResize(LevelTypes, 0);
|
|
TotalLevels = 0;
|
|
|
|
double high = iHigh(_Symbol, PERIOD_CURRENT, 1);
|
|
double low = iLow(_Symbol, PERIOD_CURRENT, 1);
|
|
|
|
for(int i=2; i<=Lookback_Bars; i++)
|
|
{
|
|
double h = iHigh(_Symbol, PERIOD_CURRENT, i);
|
|
double l = iLow(_Symbol, PERIOD_CURRENT, i);
|
|
if(h > high) high = h;
|
|
if(l < low) low = l;
|
|
}
|
|
|
|
double range = high - low;
|
|
|
|
// Fibonacci levels
|
|
AddLevel(low, "FIB_0.0");
|
|
AddLevel(low + range * 0.236, "FIB_0.236");
|
|
AddLevel(low + range * 0.382, "FIB_0.382");
|
|
AddLevel(low + range * 0.5, "FIB_0.5");
|
|
AddLevel(low + range * 0.618, "FIB_0.618");
|
|
AddLevel(low + range * 0.786, "FIB_0.786");
|
|
AddLevel(high, "FIB_1.0");
|
|
AddLevel(high + range * 0.618, "FIB_1.618");
|
|
|
|
// Quarter + Eighth
|
|
AddLevel(low + range * 0.25, "QUARTER_0.25");
|
|
AddLevel(low + range * 0.75, "QUARTER_0.75");
|
|
AddLevel(low + range * 0.125, "EIGHTH_0.125");
|
|
AddLevel(low + range * 0.375, "EIGHTH_0.375");
|
|
AddLevel(low + range * 0.625, "EIGHTH_0.625");
|
|
AddLevel(low + range * 0.875, "EIGHTH_0.875");
|
|
|
|
Print("Levels calculated: ", TotalLevels);
|
|
}
|
|
|
|
void AddLevel(double price, string type)
|
|
{
|
|
int size = ArraySize(PriceLevels);
|
|
ArrayResize(PriceLevels, size+1);
|
|
ArrayResize(LevelTypes, size+1);
|
|
PriceLevels[size] = price;
|
|
LevelTypes[size] = type;
|
|
TotalLevels++;
|
|
}
|
|
|
|
void DrawLevels()
|
|
{
|
|
ObjectsDeleteAll(0, "Level_");
|
|
for(int i=0; i<TotalLevels; i++)
|
|
{
|
|
string name = "Level_" + IntegerToString(i);
|
|
color clr = clrGray;
|
|
int width = 1;
|
|
|
|
if(StringFind(LevelTypes[i], "FIB_0.5") >= 0 ||
|
|
StringFind(LevelTypes[i], "FIB_0.618") >= 0)
|
|
{
|
|
clr = clrYellow;
|
|
width = 2;
|
|
}
|
|
else if(StringFind(LevelTypes[i], "FIB") >= 0)
|
|
{
|
|
clr = clrDodgerBlue;
|
|
}
|
|
|
|
ObjectCreate(0, name, OBJ_HLINE, 0, 0, PriceLevels[i]);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
|
|
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
|
|
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, LevelTypes[i]);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void UpdateMAs()
|
|
{
|
|
for(int i=0; i<10; i++)
|
|
{
|
|
double curr[1], prev[1];
|
|
CopyBuffer(MA_Handles[i], 0, 0, 1, curr);
|
|
CopyBuffer(MA_Handles[i], 0, 1, 1, prev);
|
|
MA_Current[i] = curr[0];
|
|
MA_Previous[i] = prev[0];
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| COUNT ALIGNED MAs (Strength detector)
|
|
//+------------------------------------------------------------------+
|
|
int CountAlignedMAs(bool bullish)
|
|
{
|
|
UpdateMAs();
|
|
int aligned = 0;
|
|
|
|
// Check all MAs for proper stacking
|
|
for(int i=0; i<9; i++)
|
|
{
|
|
if(bullish)
|
|
{
|
|
if(MA_Current[i] > MA_Current[i+1])
|
|
aligned++;
|
|
}
|
|
else
|
|
{
|
|
if(MA_Current[i] < MA_Current[i+1])
|
|
aligned++;
|
|
}
|
|
}
|
|
|
|
return aligned;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CHECK IF PRICE TOUCHING STRONG MA (230+)
|
|
//+------------------------------------------------------------------+
|
|
bool IsPriceAtStrongMA(double price, bool &at_ma230, bool &at_ma500, bool &at_ma1000)
|
|
{
|
|
double buffer = MA_Touch_Buffer_Points * _Point;
|
|
|
|
at_ma230 = MathAbs(price - MA_Current[5]) <= buffer;
|
|
at_ma500 = MathAbs(price - MA_Current[6]) <= buffer;
|
|
at_ma1000 = MathAbs(price - MA_Current[7]) <= buffer;
|
|
|
|
return (at_ma230 || at_ma500 || at_ma1000);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CHECK FOR LIQUIDITY SWEEP
|
|
//+------------------------------------------------------------------+
|
|
bool IsLiquiditySweep(double current_price, bool check_buy, bool &is_fib)
|
|
{
|
|
if(!Trade_Liquidity_Sweeps) return false;
|
|
|
|
is_fib = false;
|
|
double sweep_dist = Sweep_Detection_Points * _Point;
|
|
|
|
// Look for recent price that swept past a level then reversed
|
|
for(int i=0; i<TotalLevels; i++)
|
|
{
|
|
double level = PriceLevels[i];
|
|
|
|
// Check if this is a Fib level
|
|
bool level_is_fib = StringFind(LevelTypes[i], "FIB") >= 0;
|
|
if(Only_Sweep_At_Fib && !level_is_fib) continue;
|
|
|
|
if(check_buy)
|
|
{
|
|
// Bullish sweep: Price dropped below level, now back above
|
|
double low_recent = iLow(_Symbol, PERIOD_CURRENT, 1);
|
|
double low_2 = iLow(_Symbol, PERIOD_CURRENT, 2);
|
|
|
|
if((low_recent < level || low_2 < level) && current_price > level + sweep_dist)
|
|
{
|
|
is_fib = level_is_fib;
|
|
Print("LIQUIDITY SWEEP detected: Bulls | Level: ", level, " | Type: ", LevelTypes[i]);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bearish sweep: Price spiked above level, now back below
|
|
double high_recent = iHigh(_Symbol, PERIOD_CURRENT, 1);
|
|
double high_2 = iHigh(_Symbol, PERIOD_CURRENT, 2);
|
|
|
|
if((high_recent > level || high_2 > level) && current_price < level - sweep_dist)
|
|
{
|
|
is_fib = level_is_fib;
|
|
Print("LIQUIDITY SWEEP detected: Bears | Level: ", level, " | Type: ", LevelTypes[i]);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool IsPriceAtLevel(double price)
|
|
{
|
|
double buffer = Level_Buffer_Points * _Point;
|
|
for(int i=0; i<TotalLevels; i++)
|
|
if(MathAbs(price - PriceLevels[i]) <= buffer)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
double GetLotSize(int sl_points, int ma_strength)
|
|
{
|
|
// Adjust risk based on strength
|
|
double risk_multiplier = 1.0;
|
|
if(ma_strength >= Strong_Aligned_Count)
|
|
risk_multiplier = 1.2; // Take 20% more risk on strong setups
|
|
|
|
double risk = AccountInfoDouble(ACCOUNT_BALANCE) * Risk_Per_Trade * risk_multiplier / 100.0;
|
|
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
double lot = risk / ((sl_points * _Point / tickSize) * tickValue);
|
|
|
|
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
lot = MathMax(lot, minLot);
|
|
lot = MathMin(lot, maxLot);
|
|
lot = NormalizeDouble(lot / step, 0) * step;
|
|
|
|
return lot;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CheckLimits()
|
|
{
|
|
MqlDateTime dt;
|
|
TimeCurrent(dt);
|
|
dt.hour = 0; dt.min = 0; dt.sec = 0;
|
|
datetime today = StructToTime(dt);
|
|
|
|
if(today != LastDay)
|
|
{
|
|
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
TodayTrades = 0;
|
|
LastDay = today;
|
|
}
|
|
|
|
if(TodayTrades >= Max_Trades_Per_Day) return false;
|
|
|
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
double pl = ((balance - DailyStart) / DailyStart) * 100.0;
|
|
|
|
if(pl <= -Max_Daily_Loss_Percent || pl >= Max_Daily_Profit_Percent)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OpenTrade(bool buy, double price, int ma_strength, string reason)
|
|
{
|
|
// Determine SL size based on strength
|
|
int sl_points = Initial_SL_Points;
|
|
if(Use_Wider_SL_On_Strong && ma_strength >= Strong_Aligned_Count)
|
|
sl_points = Strong_Signal_SL_Points;
|
|
|
|
double lot = GetLotSize(sl_points, ma_strength);
|
|
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
|
|
|
|
double sl = buy ? price - sl_points * _Point : price + sl_points * _Point;
|
|
|
|
string strength_text = "WEAK";
|
|
if(ma_strength >= Strong_Aligned_Count) strength_text = "STRONG";
|
|
else if(ma_strength >= 4) strength_text = "MEDIUM";
|
|
|
|
string comment = strength_text + " | " + IntegerToString(ma_strength) + "MAs | " + reason;
|
|
|
|
bool result = false;
|
|
if(buy)
|
|
result = Trade.Buy(lot, _Symbol, price, sl, 0, comment);
|
|
else
|
|
result = Trade.Sell(lot, _Symbol, price, sl, 0, comment);
|
|
|
|
if(result)
|
|
{
|
|
TodayTrades++;
|
|
ulong ticket = Trade.ResultOrder();
|
|
|
|
int size = ArraySize(OpenPositions);
|
|
ArrayResize(OpenPositions, size+1);
|
|
OpenPositions[size].ticket = ticket;
|
|
OpenPositions[size].entry = price;
|
|
OpenPositions[size].original_lot = lot;
|
|
OpenPositions[size].is_buy = buy;
|
|
OpenPositions[size].ma_strength = ma_strength;
|
|
OpenPositions[size].tp_ma6_hit = false;
|
|
OpenPositions[size].tp_ma7_hit = false;
|
|
OpenPositions[size].tp_ma8_hit = false;
|
|
OpenPositions[size].tp_ma9_hit = false;
|
|
|
|
Print("========== TRADE ", TodayTrades, " ==========");
|
|
Print(buy ? "BUY" : "SELL", " @ ", price);
|
|
Print("Strength: ", strength_text, " (", ma_strength, " MAs)");
|
|
Print("SL: ", sl_points, " points");
|
|
Print("Reason: ", reason);
|
|
Print("===================================");
|
|
|
|
// Draw arrow
|
|
string arrow_name = "Arrow_" + IntegerToString(ticket);
|
|
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, TimeCurrent(), price);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, buy ? clrLime : clrRed);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, buy ? 233 : 234);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 3);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void ManagePositions()
|
|
{
|
|
UpdateMAs();
|
|
|
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
|
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
|
|
|
|
int idx = -1;
|
|
for(int j=0; j<ArraySize(OpenPositions); j++)
|
|
if(OpenPositions[j].ticket == ticket)
|
|
{
|
|
idx = j;
|
|
break;
|
|
}
|
|
|
|
if(idx == -1) continue;
|
|
|
|
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double sl = PositionGetDouble(POSITION_SL);
|
|
bool is_buy = OpenPositions[idx].is_buy;
|
|
int strength = OpenPositions[idx].ma_strength;
|
|
|
|
double current = is_buy ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
|
|
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
|
|
double profit_points = is_buy ? (current - entry) / _Point
|
|
: (entry - current) / _Point;
|
|
|
|
// Breakeven (later for strong signals)
|
|
int be_threshold = BreakEven_Points;
|
|
if(strength >= Strong_Aligned_Count)
|
|
be_threshold = BreakEven_Points + 50; // Give it more room
|
|
|
|
if(profit_points >= be_threshold)
|
|
{
|
|
if((is_buy && sl < entry) || (!is_buy && sl > entry))
|
|
{
|
|
Trade.PositionModify(ticket, entry, 0);
|
|
Print("BE: Position ", ticket, " | Strength: ", strength);
|
|
}
|
|
}
|
|
|
|
double lot = PositionGetDouble(POSITION_VOLUME);
|
|
|
|
// DYNAMIC TP based on strength
|
|
double close_ma6_pct, close_ma7_pct, close_ma8_pct;
|
|
|
|
if(strength >= Strong_Aligned_Count)
|
|
{
|
|
close_ma6_pct = Strong_Close_At_MA6;
|
|
close_ma7_pct = Strong_Close_At_MA7;
|
|
close_ma8_pct = Strong_Close_At_MA8;
|
|
}
|
|
else if(strength >= 4)
|
|
{
|
|
close_ma6_pct = Medium_Close_At_MA6;
|
|
close_ma7_pct = Medium_Close_At_MA7;
|
|
close_ma8_pct = Medium_Close_At_MA8;
|
|
}
|
|
else
|
|
{
|
|
close_ma6_pct = Weak_Close_At_MA6;
|
|
close_ma7_pct = Weak_Close_At_MA7;
|
|
close_ma8_pct = Weak_Close_At_MA8;
|
|
}
|
|
|
|
// TP at MA 230 (Strong MA!)
|
|
if(!OpenPositions[idx].tp_ma6_hit)
|
|
{
|
|
bool hit = is_buy ? (current >= MA_Current[5]) : (current <= MA_Current[5]);
|
|
if(hit)
|
|
{
|
|
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * close_ma6_pct / 100.0, 2);
|
|
if(close_size > 0 && close_size <= lot)
|
|
{
|
|
Trade.PositionClosePartial(ticket, close_size);
|
|
OpenPositions[idx].tp_ma6_hit = true;
|
|
Print("TP: MA 230 hit | Closed ", close_ma6_pct, "% | Ticket: ", ticket);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TP at MA 500
|
|
if(!OpenPositions[idx].tp_ma7_hit)
|
|
{
|
|
bool hit = is_buy ? (current >= MA_Current[6]) : (current <= MA_Current[6]);
|
|
if(hit)
|
|
{
|
|
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * close_ma7_pct / 100.0, 2);
|
|
if(close_size > 0 && close_size <= lot)
|
|
{
|
|
Trade.PositionClosePartial(ticket, close_size);
|
|
OpenPositions[idx].tp_ma7_hit = true;
|
|
Print("TP: MA 500 hit | Closed ", close_ma7_pct, "% | Ticket: ", ticket);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TP at MA 1000
|
|
if(!OpenPositions[idx].tp_ma8_hit)
|
|
{
|
|
bool hit = is_buy ? (current >= MA_Current[7]) : (current <= MA_Current[7]);
|
|
if(hit)
|
|
{
|
|
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * close_ma8_pct / 100.0, 2);
|
|
if(close_size > 0 && close_size <= lot)
|
|
{
|
|
Trade.PositionClosePartial(ticket, close_size);
|
|
OpenPositions[idx].tp_ma8_hit = true;
|
|
Print("TP: MA 1000 hit | Closed ", close_ma8_pct, "% | Ticket: ", ticket);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Trailing - to strong MAs or fixed points
|
|
if(profit_points >= Trail_Start_Points)
|
|
{
|
|
if(Trail_To_Strong_MAs)
|
|
{
|
|
// Trail to highest broken strong MA
|
|
double trail_level = 0;
|
|
|
|
if(is_buy)
|
|
{
|
|
// Trail to highest MA below current price
|
|
if(MA_Current[5] < current && MA_Current[5] > trail_level) // 230
|
|
trail_level = MA_Current[5];
|
|
if(MA_Current[6] < current && MA_Current[6] > trail_level) // 500
|
|
trail_level = MA_Current[6];
|
|
if(MA_Current[7] < current && MA_Current[7] > trail_level) // 1000
|
|
trail_level = MA_Current[7];
|
|
if(MA_Current[8] < current && MA_Current[8] > trail_level) // 1100
|
|
trail_level = MA_Current[8];
|
|
|
|
if(trail_level > sl + Trail_Step_Points * _Point)
|
|
{
|
|
Trade.PositionModify(ticket, trail_level, 0);
|
|
Print("Trail: SL → MA level ", trail_level);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Trail to lowest MA above current price
|
|
trail_level = 999999;
|
|
if(MA_Current[5] > current && MA_Current[5] < trail_level)
|
|
trail_level = MA_Current[5];
|
|
if(MA_Current[6] > current && MA_Current[6] < trail_level)
|
|
trail_level = MA_Current[6];
|
|
if(MA_Current[7] > current && MA_Current[7] < trail_level)
|
|
trail_level = MA_Current[7];
|
|
if(MA_Current[8] > current && MA_Current[8] < trail_level)
|
|
trail_level = MA_Current[8];
|
|
|
|
if(trail_level < 999999 && trail_level < sl - Trail_Step_Points * _Point)
|
|
{
|
|
Trade.PositionModify(ticket, trail_level, 0);
|
|
Print("Trail: SL → MA level ", trail_level);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Standard trailing
|
|
double newSL = is_buy ? current - Trail_Stop_Points * _Point
|
|
: current + Trail_Stop_Points * _Point;
|
|
|
|
if((is_buy && newSL > sl + Trail_Step_Points * _Point) ||
|
|
(!is_buy && newSL < sl - Trail_Step_Points * _Point))
|
|
{
|
|
Trade.PositionModify(ticket, newSL, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
ManagePositions();
|
|
|
|
if(!CheckLimits()) return;
|
|
|
|
int open = 0;
|
|
for(int i=0; i<PositionsTotal(); i++)
|
|
{
|
|
if(PositionGetTicket(i) == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
|
|
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
|
|
open++;
|
|
}
|
|
if(open >= Max_Simultaneous_Trades) return;
|
|
|
|
static datetime last_calc = 0;
|
|
if(TimeCurrent() - last_calc > 1800)
|
|
{
|
|
CalculatePriceLevels();
|
|
if(Show_Levels) DrawLevels();
|
|
last_calc = TimeCurrent();
|
|
}
|
|
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double current = (bid + ask) / 2;
|
|
|
|
// Count aligned MAs (strength)
|
|
int bull_strength = CountAlignedMAs(true);
|
|
int bear_strength = CountAlignedMAs(false);
|
|
|
|
// Check if at price level
|
|
bool at_level = IsPriceAtLevel(current);
|
|
|
|
// Check if touching strong MAs
|
|
bool at_ma230=false, at_ma500=false, at_ma1000=false;
|
|
bool at_strong_ma = IsPriceAtStrongMA(current, at_ma230, at_ma500, at_ma1000);
|
|
|
|
// Check for liquidity sweeps
|
|
bool is_fib_sweep = false;
|
|
bool bull_sweep = IsLiquiditySweep(current, true, is_fib_sweep);
|
|
bool bear_sweep = IsLiquiditySweep(current, false, is_fib_sweep);
|
|
|
|
// === ENTRY LOGIC ===
|
|
|
|
// BUY signals
|
|
bool buy_signal = false;
|
|
string buy_reason = "";
|
|
|
|
// 1. Strong MAs aligned + at level
|
|
if(bull_strength >= Min_Aligned_For_Entry && at_level)
|
|
{
|
|
buy_signal = true;
|
|
buy_reason = IntegerToString(bull_strength) + " MAs + Level";
|
|
}
|
|
|
|
// 2. Touching strong MA (230+) + MAs aligned
|
|
if(Strong_MAs_Are_Magnets && bull_strength >= Min_Aligned_For_Entry && at_strong_ma)
|
|
{
|
|
buy_signal = true;
|
|
if(at_ma230) buy_reason = "MA 230 Kiss + " + IntegerToString(bull_strength) + " MAs";
|
|
else if(at_ma500) buy_reason = "MA 500 Kiss + " + IntegerToString(bull_strength) + " MAs";
|
|
else if(at_ma1000) buy_reason = "MA 1000 Kiss + " + IntegerToString(bull_strength) + " MAs";
|
|
}
|
|
|
|
// 3. Liquidity sweep + strong alignment
|
|
if(bull_sweep && bull_strength >= Min_Aligned_For_Entry)
|
|
{
|
|
buy_signal = true;
|
|
buy_reason = "Liquidity Sweep (Bull) + " + IntegerToString(bull_strength) + " MAs";
|
|
}
|
|
|
|
// 4. Very strong alignment (5+) = auto entry at any level
|
|
if(bull_strength >= Strong_Aligned_Count && at_level)
|
|
{
|
|
buy_signal = true;
|
|
buy_reason = "STRONG " + IntegerToString(bull_strength) + " MAs ALIGNED!";
|
|
}
|
|
|
|
// SELL signals
|
|
bool sell_signal = false;
|
|
string sell_reason = "";
|
|
|
|
// 1. Strong MAs aligned + at level
|
|
if(bear_strength >= Min_Aligned_For_Entry && at_level)
|
|
{
|
|
sell_signal = true;
|
|
sell_reason = IntegerToString(bear_strength) + " MAs + Level";
|
|
}
|
|
|
|
// 2. Touching strong MA (230+) + MAs aligned
|
|
if(Strong_MAs_Are_Magnets && bear_strength >= Min_Aligned_For_Entry && at_strong_ma)
|
|
{
|
|
sell_signal = true;
|
|
if(at_ma230) sell_reason = "MA 230 Kiss + " + IntegerToString(bear_strength) + " MAs";
|
|
else if(at_ma500) sell_reason = "MA 500 Kiss + " + IntegerToString(bear_strength) + " MAs";
|
|
else if(at_ma1000) sell_reason = "MA 1000 Kiss + " + IntegerToString(bear_strength) + " MAs";
|
|
}
|
|
|
|
// 3. Liquidity sweep + strong alignment
|
|
if(bear_sweep && bear_strength >= Min_Aligned_For_Entry)
|
|
{
|
|
sell_signal = true;
|
|
sell_reason = "Liquidity Sweep (Bear) + " + IntegerToString(bear_strength) + " MAs";
|
|
}
|
|
|
|
// 4. Very strong alignment (5+) = auto entry
|
|
if(bear_strength >= Strong_Aligned_Count && at_level)
|
|
{
|
|
sell_signal = true;
|
|
sell_reason = "STRONG " + IntegerToString(bear_strength) + " MAs ALIGNED!";
|
|
}
|
|
|
|
// EXECUTE
|
|
if(buy_signal)
|
|
{
|
|
OpenTrade(true, ask, bull_strength, buy_reason);
|
|
}
|
|
|
|
if(sell_signal)
|
|
{
|
|
OpenTrade(false, bid, bear_strength, sell_reason);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |