656 lines
20 KiB
MQL5
656 lines
20 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| QuarterTheory_ULTIMATE.mq5 |
|
||
|
|
//| PURE BREAK & RETEST SYSTEM - ALL LAYERS |
|
||
|
|
//| MAs Break Each Other + Price Levels Break + TRIX Levels Break |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Ultimate Break & Retest System"
|
||
|
|
#property version "6.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 = 4;
|
||
|
|
|
||
|
|
input group "=== PRICE LEVELS (Break & Retest) ==="
|
||
|
|
input int Lookback_Bars = 200;
|
||
|
|
input int Level_Buffer_Points = 30;
|
||
|
|
input bool Show_Levels = true;
|
||
|
|
|
||
|
|
input group "=== MA CROSSOVERS (Break & Retest) ==="
|
||
|
|
input int MA_1 = 7;
|
||
|
|
input int MA_2 = 14;
|
||
|
|
input int MA_3 = 21;
|
||
|
|
input int MA_4 = 50;
|
||
|
|
input int MA_5 = 140;
|
||
|
|
input int MA_6 = 230;
|
||
|
|
input int MA_7 = 500;
|
||
|
|
input int MA_8 = 1000;
|
||
|
|
input int MA_9 = 1100;
|
||
|
|
input int MA_10 = 1300;
|
||
|
|
input int Min_MA_Crosses_For_Entry = 1; // Min crosses to trigger
|
||
|
|
input int MA_Crosses_For_Extended = 2; // Crosses for bigger TP
|
||
|
|
input int MA_Crosses_For_Maximum = 3; // Crosses for max TP
|
||
|
|
|
||
|
|
input group "=== TRIX LEVELS (Break & Retest) ==="
|
||
|
|
input int TRIX_Period = 18;
|
||
|
|
input double TRIX_Level_Spacing = 25.0;
|
||
|
|
input int Min_TRIX_Breaks = 1; // Min breaks to trigger
|
||
|
|
input int TRIX_Breaks_For_Extended = 2; // Breaks for bigger TP
|
||
|
|
input int TRIX_Breaks_For_Maximum = 3; // Breaks for max TP
|
||
|
|
|
||
|
|
input group "=== CONFIRMATION RULES ==="
|
||
|
|
input bool Require_Price_Level = true; // Need price at level
|
||
|
|
input bool Require_MA_Cross = true; // Need MA cross
|
||
|
|
input bool Require_TRIX_Break = true; // Need TRIX break
|
||
|
|
|
||
|
|
input group "=== DYNAMIC TAKE PROFIT ==="
|
||
|
|
// BASE (minimum confirmations)
|
||
|
|
input int BASE_TP1 = 50;
|
||
|
|
input int BASE_TP2 = 100;
|
||
|
|
input int BASE_TP3 = 150;
|
||
|
|
input int BASE_TP4 = 250;
|
||
|
|
// EXTENDED (2+ confirmations each layer)
|
||
|
|
input int EXTENDED_TP1 = 75;
|
||
|
|
input int EXTENDED_TP2 = 150;
|
||
|
|
input int EXTENDED_TP3 = 225;
|
||
|
|
input int EXTENDED_TP4 = 400;
|
||
|
|
// MAXIMUM (3+ confirmations each layer)
|
||
|
|
input int MAXIMUM_TP1 = 100;
|
||
|
|
input int MAXIMUM_TP2 = 200;
|
||
|
|
input int MAXIMUM_TP3 = 300;
|
||
|
|
input int MAXIMUM_TP4 = 600;
|
||
|
|
|
||
|
|
input double TP1_Close_Percent = 25.0;
|
||
|
|
input double TP2_Close_Percent = 33.0;
|
||
|
|
input double TP3_Close_Percent = 25.0;
|
||
|
|
|
||
|
|
input group "=== RISK MANAGEMENT ==="
|
||
|
|
input int Initial_SL_Points = 150;
|
||
|
|
input int BreakEven_Points = 80;
|
||
|
|
input int Trailing_Start = 100;
|
||
|
|
input int Trailing_Step = 30;
|
||
|
|
input int Trailing_Stop = 40;
|
||
|
|
|
||
|
|
input group "=== DAILY LIMITS ==="
|
||
|
|
input double Max_Daily_Loss_Percent = 3.0;
|
||
|
|
input double Max_Daily_Profit_Percent = 10.0;
|
||
|
|
input int Max_Trades_Per_Day = 12;
|
||
|
|
|
||
|
|
//================ GLOBALS ==================//
|
||
|
|
double PriceLevels[];
|
||
|
|
int TotalLevels = 0;
|
||
|
|
|
||
|
|
int MA_Handles[10];
|
||
|
|
double MA_Current[10];
|
||
|
|
double MA_Previous[10];
|
||
|
|
|
||
|
|
int TRIX_Handle;
|
||
|
|
double TRIX_Current = 0;
|
||
|
|
double TRIX_Previous = 0;
|
||
|
|
double TRIX_Levels[20];
|
||
|
|
bool TRIX_Level_Broken_Up[20];
|
||
|
|
bool TRIX_Level_Broken_Down[20];
|
||
|
|
|
||
|
|
struct Position
|
||
|
|
{
|
||
|
|
ulong ticket;
|
||
|
|
double entry;
|
||
|
|
double original_lot;
|
||
|
|
int tp_mode; // 0=BASE, 1=EXTENDED, 2=MAXIMUM
|
||
|
|
int ma_crosses;
|
||
|
|
int trix_breaks;
|
||
|
|
bool tp1_hit;
|
||
|
|
bool tp2_hit;
|
||
|
|
bool tp3_hit;
|
||
|
|
};
|
||
|
|
Position OpenPositions[];
|
||
|
|
|
||
|
|
double DailyStart = 0;
|
||
|
|
int TodayTrades = 0;
|
||
|
|
datetime LastDay = 0;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit()
|
||
|
|
{
|
||
|
|
Print("========================================");
|
||
|
|
Print("ULTIMATE BREAK & RETEST SYSTEM v6.0");
|
||
|
|
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 Handle ", i, " failed");
|
||
|
|
return INIT_FAILED;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize TRIX
|
||
|
|
TRIX_Handle = iMA(_Symbol, PERIOD_CURRENT, TRIX_Period, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
|
||
|
|
// Setup TRIX levels
|
||
|
|
int idx = 0;
|
||
|
|
for(double level=-100; level<=100; level+=TRIX_Level_Spacing)
|
||
|
|
{
|
||
|
|
TRIX_Levels[idx] = level;
|
||
|
|
TRIX_Level_Broken_Up[idx] = false;
|
||
|
|
TRIX_Level_Broken_Down[idx] = false;
|
||
|
|
idx++;
|
||
|
|
}
|
||
|
|
|
||
|
|
CalculatePriceLevels();
|
||
|
|
if(Show_Levels) DrawLevels();
|
||
|
|
|
||
|
|
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
|
||
|
|
|
||
|
|
Print("Initialized | Price Levels: ", TotalLevels);
|
||
|
|
Print("MA Periods: ", MA_1, ",", MA_2, ",", MA_3, ",", MA_4, ",", MA_5, ",", MA_6, ",", MA_7, ",", MA_8, ",", MA_9, ",", MA_10);
|
||
|
|
|
||
|
|
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_");
|
||
|
|
Print("EA Stopped");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CALCULATE PRICE LEVELS (Keep dividing in half)
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalculatePriceLevels()
|
||
|
|
{
|
||
|
|
ArrayResize(PriceLevels, 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;
|
||
|
|
|
||
|
|
// Keep dividing in half (binary division)
|
||
|
|
AddLevel(low); // 0.0
|
||
|
|
AddLevel(high); // 1.0
|
||
|
|
AddLevel(low + range * 0.5); // 0.5 (half)
|
||
|
|
AddLevel(low + range * 0.25); // 0.25 (quarter)
|
||
|
|
AddLevel(low + range * 0.75); // 0.75 (quarter)
|
||
|
|
AddLevel(low + range * 0.125); // 0.125 (eighth)
|
||
|
|
AddLevel(low + range * 0.375); // 0.375 (eighth)
|
||
|
|
AddLevel(low + range * 0.625); // 0.625 (eighth)
|
||
|
|
AddLevel(low + range * 0.875); // 0.875 (eighth)
|
||
|
|
|
||
|
|
// Fibonacci (for extra precision)
|
||
|
|
AddLevel(low + range * 0.236);
|
||
|
|
AddLevel(low + range * 0.382);
|
||
|
|
AddLevel(low + range * 0.618);
|
||
|
|
AddLevel(low + range * 0.786);
|
||
|
|
AddLevel(high + range * 0.618); // Extension
|
||
|
|
|
||
|
|
// Sort
|
||
|
|
for(int i=0; i<TotalLevels-1; i++)
|
||
|
|
for(int j=i+1; j<TotalLevels; j++)
|
||
|
|
if(PriceLevels[j] < PriceLevels[i])
|
||
|
|
{
|
||
|
|
double temp = PriceLevels[i];
|
||
|
|
PriceLevels[i] = PriceLevels[j];
|
||
|
|
PriceLevels[j] = temp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void AddLevel(double price)
|
||
|
|
{
|
||
|
|
int size = ArraySize(PriceLevels);
|
||
|
|
ArrayResize(PriceLevels, size+1);
|
||
|
|
PriceLevels[size] = price;
|
||
|
|
TotalLevels++;
|
||
|
|
}
|
||
|
|
|
||
|
|
void DrawLevels()
|
||
|
|
{
|
||
|
|
ObjectsDeleteAll(0, "Level_");
|
||
|
|
for(int i=0; i<TotalLevels; i++)
|
||
|
|
{
|
||
|
|
string name = "Level_" + IntegerToString(i);
|
||
|
|
ObjectCreate(0, name, OBJ_HLINE, 0, 0, PriceLevels[i]);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
|
||
|
|
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| UPDATE MA VALUES & DETECT CROSSES
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CountMACrosses(bool bullish)
|
||
|
|
{
|
||
|
|
// Get current and previous MA values
|
||
|
|
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];
|
||
|
|
}
|
||
|
|
|
||
|
|
int crosses = 0;
|
||
|
|
|
||
|
|
// Count crosses: lower MA crossing higher MA
|
||
|
|
for(int i=0; i<9; i++)
|
||
|
|
{
|
||
|
|
for(int j=i+1; j<10; j++)
|
||
|
|
{
|
||
|
|
if(bullish)
|
||
|
|
{
|
||
|
|
// Lower MA crosses ABOVE higher MA = bullish
|
||
|
|
if(MA_Previous[i] <= MA_Previous[j] && MA_Current[i] > MA_Current[j])
|
||
|
|
crosses++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Lower MA crosses BELOW higher MA = bearish
|
||
|
|
if(MA_Previous[i] >= MA_Previous[j] && MA_Current[i] < MA_Current[j])
|
||
|
|
crosses++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return crosses;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| UPDATE TRIX & DETECT LEVEL BREAKS
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CountTRIXBreaks(bool bullish)
|
||
|
|
{
|
||
|
|
double buf[2];
|
||
|
|
CopyBuffer(TRIX_Handle, 0, 0, 2, buf);
|
||
|
|
|
||
|
|
TRIX_Previous = TRIX_Current;
|
||
|
|
TRIX_Current = ((buf[0] - buf[1]) / buf[1]) * 10000; // Scale TRIX
|
||
|
|
|
||
|
|
// Detect breaks
|
||
|
|
for(int i=0; i<20; i++)
|
||
|
|
{
|
||
|
|
double level = TRIX_Levels[i];
|
||
|
|
|
||
|
|
// Upward break
|
||
|
|
if(TRIX_Previous < level && TRIX_Current >= level)
|
||
|
|
TRIX_Level_Broken_Up[i] = true;
|
||
|
|
|
||
|
|
// Downward break
|
||
|
|
if(TRIX_Previous > level && TRIX_Current <= level)
|
||
|
|
TRIX_Level_Broken_Down[i] = true;
|
||
|
|
|
||
|
|
// Reset after 4 hours
|
||
|
|
// (simplified - in production track break time)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Count breaks in direction
|
||
|
|
int breaks = 0;
|
||
|
|
for(int i=0; i<20; i++)
|
||
|
|
{
|
||
|
|
if(bullish && TRIX_Level_Broken_Up[i] && TRIX_Levels[i] > 0)
|
||
|
|
breaks++;
|
||
|
|
if(!bullish && TRIX_Level_Broken_Down[i] && TRIX_Levels[i] < 0)
|
||
|
|
breaks++;
|
||
|
|
}
|
||
|
|
|
||
|
|
return breaks;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CHECK IF PRICE AT LEVEL
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| DETERMINE TP MODE BASED ON TOTAL CONFIRMATIONS
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int DetermineTPMode(int ma_crosses, int trix_breaks)
|
||
|
|
{
|
||
|
|
// Count total confirmation strength
|
||
|
|
int total_strength = 0;
|
||
|
|
|
||
|
|
if(ma_crosses >= MA_Crosses_For_Maximum) total_strength++;
|
||
|
|
else if(ma_crosses >= MA_Crosses_For_Extended) total_strength++;
|
||
|
|
|
||
|
|
if(trix_breaks >= TRIX_Breaks_For_Maximum) total_strength++;
|
||
|
|
else if(trix_breaks >= TRIX_Breaks_For_Extended) total_strength++;
|
||
|
|
|
||
|
|
// Determine mode
|
||
|
|
if(total_strength >= 2) return 2; // MAXIMUM (both strong)
|
||
|
|
if(total_strength >= 1) return 1; // EXTENDED (one strong)
|
||
|
|
return 0; // BASE
|
||
|
|
}
|
||
|
|
|
||
|
|
void GetTPTargets(int mode, int &tp1, int &tp2, int &tp3, int &tp4)
|
||
|
|
{
|
||
|
|
if(mode == 2)
|
||
|
|
{
|
||
|
|
tp1 = MAXIMUM_TP1;
|
||
|
|
tp2 = MAXIMUM_TP2;
|
||
|
|
tp3 = MAXIMUM_TP3;
|
||
|
|
tp4 = MAXIMUM_TP4;
|
||
|
|
}
|
||
|
|
else if(mode == 1)
|
||
|
|
{
|
||
|
|
tp1 = EXTENDED_TP1;
|
||
|
|
tp2 = EXTENDED_TP2;
|
||
|
|
tp3 = EXTENDED_TP3;
|
||
|
|
tp4 = EXTENDED_TP4;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
tp1 = BASE_TP1;
|
||
|
|
tp2 = BASE_TP2;
|
||
|
|
tp3 = BASE_TP3;
|
||
|
|
tp4 = BASE_TP4;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CALCULATE LOT SIZE
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double GetLotSize(int sl_points)
|
||
|
|
{
|
||
|
|
double risk = AccountInfoDouble(ACCOUNT_BALANCE) * Risk_Per_Trade / 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CHECK DAILY LIMITS
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| OPEN TRADE
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OpenTrade(bool buy, double price, int ma_crosses, int trix_breaks)
|
||
|
|
{
|
||
|
|
double lot = GetLotSize(Initial_SL_Points);
|
||
|
|
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
|
||
|
|
|
||
|
|
int mode = DetermineTPMode(ma_crosses, trix_breaks);
|
||
|
|
|
||
|
|
string mode_text = "BASE";
|
||
|
|
if(mode == 1) mode_text = "EXTENDED";
|
||
|
|
if(mode == 2) mode_text = "MAXIMUM";
|
||
|
|
|
||
|
|
double sl = buy ? price - Initial_SL_Points * _Point : price + Initial_SL_Points * _Point;
|
||
|
|
|
||
|
|
string comment = "MA:" + IntegerToString(ma_crosses) +
|
||
|
|
" TRIX:" + IntegerToString(trix_breaks) +
|
||
|
|
" " + mode_text;
|
||
|
|
|
||
|
|
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].tp_mode = mode;
|
||
|
|
OpenPositions[size].ma_crosses = ma_crosses;
|
||
|
|
OpenPositions[size].trix_breaks = trix_breaks;
|
||
|
|
OpenPositions[size].tp1_hit = false;
|
||
|
|
OpenPositions[size].tp2_hit = false;
|
||
|
|
OpenPositions[size].tp3_hit = false;
|
||
|
|
|
||
|
|
Print("===== TRADE OPENED =====");
|
||
|
|
Print("Direction: ", buy ? "BUY" : "SELL");
|
||
|
|
Print("MA Crosses: ", ma_crosses);
|
||
|
|
Print("TRIX Breaks: ", trix_breaks);
|
||
|
|
Print("TP Mode: ", mode_text);
|
||
|
|
Print("========================");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| MANAGE POSITIONS
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void ManagePositions()
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
|
||
|
|
// Find in our tracking
|
||
|
|
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);
|
||
|
|
long type = PositionGetInteger(POSITION_TYPE);
|
||
|
|
|
||
|
|
double current = (type == POSITION_TYPE_BUY)
|
||
|
|
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
|
||
|
|
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
|
||
|
|
double profit_points = (type == POSITION_TYPE_BUY)
|
||
|
|
? (current - entry) / _Point
|
||
|
|
: (entry - current) / _Point;
|
||
|
|
|
||
|
|
// Breakeven
|
||
|
|
if(profit_points >= BreakEven_Points)
|
||
|
|
{
|
||
|
|
if((type == POSITION_TYPE_BUY && sl < entry) || (type == POSITION_TYPE_SELL && sl > entry))
|
||
|
|
{
|
||
|
|
double newSL = entry;
|
||
|
|
Trade.PositionModify(ticket, newSL, 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Partial TPs
|
||
|
|
int tp1, tp2, tp3, tp4;
|
||
|
|
GetTPTargets(OpenPositions[idx].tp_mode, tp1, tp2, tp3, tp4);
|
||
|
|
|
||
|
|
double lot = PositionGetDouble(POSITION_VOLUME);
|
||
|
|
|
||
|
|
if(!OpenPositions[idx].tp1_hit && profit_points >= tp1)
|
||
|
|
{
|
||
|
|
double close = NormalizeDouble(OpenPositions[idx].original_lot * TP1_Close_Percent / 100, 2);
|
||
|
|
if(close > 0 && close <= lot)
|
||
|
|
{
|
||
|
|
Trade.PositionClosePartial(ticket, close);
|
||
|
|
OpenPositions[idx].tp1_hit = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!OpenPositions[idx].tp2_hit && profit_points >= tp2)
|
||
|
|
{
|
||
|
|
double close = NormalizeDouble(OpenPositions[idx].original_lot * TP2_Close_Percent / 100, 2);
|
||
|
|
if(close > 0 && close <= lot)
|
||
|
|
{
|
||
|
|
Trade.PositionClosePartial(ticket, close);
|
||
|
|
OpenPositions[idx].tp2_hit = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!OpenPositions[idx].tp3_hit && profit_points >= tp3)
|
||
|
|
{
|
||
|
|
double close = NormalizeDouble(OpenPositions[idx].original_lot * TP3_Close_Percent / 100, 2);
|
||
|
|
if(close > 0 && close <= lot)
|
||
|
|
{
|
||
|
|
Trade.PositionClosePartial(ticket, close);
|
||
|
|
OpenPositions[idx].tp3_hit = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Trailing
|
||
|
|
if(profit_points >= Trailing_Start)
|
||
|
|
{
|
||
|
|
double newSL = 0;
|
||
|
|
if(type == POSITION_TYPE_BUY)
|
||
|
|
{
|
||
|
|
newSL = current - Trailing_Stop * _Point;
|
||
|
|
if(newSL > sl + Trailing_Step * _Point)
|
||
|
|
Trade.PositionModify(ticket, newSL, 0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
newSL = current + Trailing_Stop * _Point;
|
||
|
|
if(newSL < sl - Trailing_Step * _Point)
|
||
|
|
Trade.PositionModify(ticket, newSL, 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| MAIN TICK
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnTick()
|
||
|
|
{
|
||
|
|
ManagePositions();
|
||
|
|
|
||
|
|
// Check limits
|
||
|
|
if(!CheckLimits()) return;
|
||
|
|
|
||
|
|
// Count open positions
|
||
|
|
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;
|
||
|
|
|
||
|
|
// Recalculate levels hourly
|
||
|
|
static datetime last_calc = 0;
|
||
|
|
if(TimeCurrent() - last_calc > 3600)
|
||
|
|
{
|
||
|
|
CalculatePriceLevels();
|
||
|
|
if(Show_Levels) DrawLevels();
|
||
|
|
last_calc = TimeCurrent();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get current price
|
||
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
double price = (bid + ask) / 2;
|
||
|
|
|
||
|
|
// CHECK ALL BREAK & RETEST CONDITIONS
|
||
|
|
|
||
|
|
// 1. Price at level?
|
||
|
|
bool price_at_level = IsPriceAtLevel(price);
|
||
|
|
if(Require_Price_Level && !price_at_level) return;
|
||
|
|
|
||
|
|
// 2. MA crosses (lower MA breaking higher MA)
|
||
|
|
int ma_crosses_bull = CountMACrosses(true);
|
||
|
|
int ma_crosses_bear = CountMACrosses(false);
|
||
|
|
|
||
|
|
if(Require_MA_Cross && ma_crosses_bull < Min_MA_Crosses_For_Entry &&
|
||
|
|
ma_crosses_bear < Min_MA_Crosses_For_Entry) return;
|
||
|
|
|
||
|
|
// 3. TRIX level breaks
|
||
|
|
int trix_breaks_bull = CountTRIXBreaks(true);
|
||
|
|
int trix_breaks_bear = CountTRIXBreaks(false);
|
||
|
|
|
||
|
|
if(Require_TRIX_Break && trix_breaks_bull < Min_TRIX_Breaks &&
|
||
|
|
trix_breaks_bear < Min_TRIX_Breaks) return;
|
||
|
|
|
||
|
|
// ENTRY LOGIC
|
||
|
|
|
||
|
|
// BUY: Lower MAs breaking above higher MAs + TRIX breaking up
|
||
|
|
if(ma_crosses_bull >= Min_MA_Crosses_For_Entry && trix_breaks_bull >= Min_TRIX_Breaks)
|
||
|
|
{
|
||
|
|
OpenTrade(true, ask, ma_crosses_bull, trix_breaks_bull);
|
||
|
|
}
|
||
|
|
|
||
|
|
// SELL: Lower MAs breaking below higher MAs + TRIX breaking down
|
||
|
|
if(ma_crosses_bear >= Min_MA_Crosses_For_Entry && trix_breaks_bear >= Min_TRIX_Breaks)
|
||
|
|
{
|
||
|
|
OpenTrade(false, bid, ma_crosses_bear, trix_breaks_bear);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|