//+------------------------------------------------------------------+ //| QuarterTheory_FINAL_RR.mq5 | //| 1:5 RR Fib-Based SL/TP + 25% Partials + Trend Reversal | //| BE at 300pts | Trail 500pts | Close Opposites | //+------------------------------------------------------------------+ #property copyright "Final Risk-Reward System" #property version "15.00" #property strict #include CTrade Trade; //================ INPUT PARAMETERS ==================// input group "=== GENERAL ===" input int MagicNumber = 456789; input double Risk_Per_Trade = 1.2; input int Min_Active_Entries = 8; input int Max_Simultaneous_Trades = 20; input group "=== MA TREND BIAS (PRIMARY!) ===" 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 bool Require_MA_Trend_Bias = true; input int Min_MA7_Crosses = 2; input group "=== STOCHASTIC (SECONDARY) ===" input int Stoch_K_Period = 5; input int Stoch_D_Period = 3; input int Stoch_Slowing = 3; input double Stoch_Overbought = 80.0; input double Stoch_Oversold = 20.0; input bool Use_Stoch_Confirmation = true; input group "=== HIGHER MA RE-ENTRY ===" input bool ReEnter_At_MA50 = true; input bool ReEnter_At_MA140 = true; input bool ReEnter_At_MA230 = true; input bool ReEnter_At_MA500 = true; input int MA_Touch_Buffer = 30; input group "=== FIBONACCI LEVELS ===" input int Lookback_Bars = 200; input bool Show_Levels = true; input group "=== RISK MANAGEMENT (1:5 RR) ===" input double Risk_Reward_Ratio = 5.0; // 1:5 RR input bool Use_Fib_Based_SLTP = true; // SL/TP to nearest Fib input int Move_BE_At_Points = 300; // Move to BE input int Trailing_SL_Points = 500; // Trailing distance input double Partial_TP_Percent = 25.0; // Close 25% per hit input group "=== DAILY LIMITS ===" input double Max_Daily_Loss_Percent = 5.0; input double Max_Daily_Profit_Percent = 30.0; input int Max_Trades_Per_Day = 40; //================ GLOBALS ==================// int Stoch_Handle; double Stoch_K_Current = 0; double Stoch_K_Previous = 0; double PriceLevels[]; string LevelTypes[]; int TotalLevels = 0; int MA_Handles[10]; double MA_Current[10]; double MA_Previous[10]; bool Current_Trend_Bullish = false; bool Current_Trend_Bearish = false; bool Previous_Trend_Bullish = false; bool Previous_Trend_Bearish = false; datetime Last_Trend_Check = 0; struct Position { ulong ticket; double entry; double sl_level; double tp_level; double original_lot; bool is_buy; bool be_set; int partials_closed; }; Position OpenPositions[]; double DailyStart = 0; int TodayTrades = 0; datetime LastDay = 0; //+------------------------------------------------------------------+ int OnInit() { Print("========================================"); Print("FINAL RR SYSTEM v15.0"); Print("1:5 RR | Fib-Based SL/TP"); Print("25% Partials | Close Opposites"); Print("========================================"); Trade.SetExpertMagicNumber(MagicNumber); Trade.SetDeviationInPoints(50); Stoch_Handle = iStochastic(_Symbol, PERIOD_CURRENT, Stoch_K_Period, Stoch_D_Period, Stoch_Slowing, MODE_SMA, STO_LOWHIGH); if(Stoch_Handle == INVALID_HANDLE) { Print("ERROR: Stochastic failed"); return INIT_FAILED; } 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; } } CalculatePriceLevels(); if(Show_Levels) DrawLevels(); DailyStart = AccountInfoDouble(ACCOUNT_BALANCE); Print("Risk:Reward = 1:", Risk_Reward_Ratio); Print("BE at: ", Move_BE_At_Points, " points"); Print("Partial TP: ", Partial_TP_Percent, "% per MA/Fib hit"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { for(int i=0; i<10; i++) if(MA_Handles[i] != INVALID_HANDLE) IndicatorRelease(MA_Handles[i]); if(Stoch_Handle != INVALID_HANDLE) IndicatorRelease(Stoch_Handle); ObjectsDeleteAll(0, "Level_"); ObjectsDeleteAll(0, "Arrow_"); ObjectsDeleteAll(0, "TrendLabel"); } //+------------------------------------------------------------------+ void CalculatePriceLevels() { ArrayResize(PriceLevels, 0); ArrayResize(LevelTypes, 0); TotalLevels = 0; double high = iHigh(_Symbol, PERIOD_CURRENT, 0); double low = iLow(_Symbol, PERIOD_CURRENT, 0); for(int i=1; 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; int size = 0; ArrayResize(PriceLevels, 10); ArrayResize(LevelTypes, 10); PriceLevels[size] = low; LevelTypes[size] = "FIB_0.0"; size++; PriceLevels[size] = low + range * 0.236; LevelTypes[size] = "FIB_0.236"; size++; PriceLevels[size] = low + range * 0.382; LevelTypes[size] = "FIB_0.382"; size++; PriceLevels[size] = low + range * 0.5; LevelTypes[size] = "FIB_0.5"; size++; PriceLevels[size] = low + range * 0.618; LevelTypes[size] = "FIB_0.618"; size++; PriceLevels[size] = low + range * 0.786; LevelTypes[size] = "FIB_0.786"; size++; PriceLevels[size] = high; LevelTypes[size] = "FIB_1.0"; size++; TotalLevels = size; } void DrawLevels() { ObjectsDeleteAll(0, "Level_"); for(int i=0; i 0) MA_Current[i] = curr[0]; if(CopyBuffer(MA_Handles[i], 0, 1, 1, prev) > 0) MA_Previous[i] = prev[0]; } } void UpdateStochastic() { double k_curr[1], k_prev[1]; if(CopyBuffer(Stoch_Handle, MAIN_LINE, 0, 1, k_curr) > 0) Stoch_K_Current = k_curr[0]; if(CopyBuffer(Stoch_Handle, MAIN_LINE, 1, 1, k_prev) > 0) Stoch_K_Previous = k_prev[0]; } //+------------------------------------------------------------------+ //| FIND NEAREST FIB LEVEL //+------------------------------------------------------------------+ double FindNearestFibLevel(double price, bool find_below) { double nearest = 0; double min_distance = 999999; for(int i=0; i price && distance < min_distance) { nearest = level; min_distance = distance; } } return nearest; } //+------------------------------------------------------------------+ //| CALCULATE DYNAMIC SL/TP //+------------------------------------------------------------------+ void CalculateDynamicSLTP(double entry, bool is_buy, double &sl, double &tp) { if(Use_Fib_Based_SLTP && TotalLevels > 0) { // SL = nearest Fib below entry (buy) or above (sell) sl = FindNearestFibLevel(entry, is_buy); if(sl == 0 || MathAbs(entry - sl) / _Point < 100) sl = is_buy ? entry - 800 * _Point : entry + 800 * _Point; // TP = entry + (risk * RR ratio) double sl_distance = MathAbs(entry - sl); tp = is_buy ? entry + (sl_distance * Risk_Reward_Ratio) : entry - (sl_distance * Risk_Reward_Ratio); // Adjust TP to nearest Fib if close double nearest_tp_fib = FindNearestFibLevel(entry, !is_buy); if(nearest_tp_fib != 0) { double calculated_tp_dist = MathAbs(tp - entry); double fib_tp_dist = MathAbs(nearest_tp_fib - entry); if(MathAbs(calculated_tp_dist - fib_tp_dist) / calculated_tp_dist < 0.15) tp = nearest_tp_fib; } Print("SL/TP: Entry=", entry, " SL=", sl, " (", (int)(MathAbs(entry-sl)/_Point), "pts) | TP=", tp, " (", (int)(MathAbs(tp-entry)/_Point), "pts) | RR=1:", DoubleToString(MathAbs(tp-entry)/MathAbs(entry-sl),1)); } else { sl = is_buy ? entry - 800 * _Point : entry + 800 * _Point; tp = is_buy ? entry + 4000 * _Point : entry - 4000 * _Point; } } //+------------------------------------------------------------------+ void DetermineTrendBias() { UpdateMAs(); Previous_Trend_Bullish = Current_Trend_Bullish; Previous_Trend_Bearish = Current_Trend_Bearish; int bullish_alignment = 0; int bearish_alignment = 0; for(int i=0; i<6; i++) { if(i < 5 && MA_Current[i] > MA_Current[i+1]) bullish_alignment++; if(i < 5 && MA_Current[i] < MA_Current[i+1]) bearish_alignment++; } bool ma7_above_ma50 = MA_Current[0] > MA_Current[3]; bool ma7_below_ma50 = MA_Current[0] < MA_Current[3]; if(bullish_alignment >= 3 && ma7_above_ma50) { Current_Trend_Bullish = true; Current_Trend_Bearish = false; } else if(bearish_alignment >= 3 && ma7_below_ma50) { Current_Trend_Bullish = false; Current_Trend_Bearish = true; } ObjectDelete(0, "TrendLabel"); ObjectCreate(0, "TrendLabel", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "TrendLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "TrendLabel", OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, "TrendLabel", OBJPROP_YDISTANCE, 30); if(Current_Trend_Bullish) { ObjectSetString(0, "TrendLabel", OBJPROP_TEXT, "TREND: BULLISH ↑"); ObjectSetInteger(0, "TrendLabel", OBJPROP_COLOR, clrLime); } else if(Current_Trend_Bearish) { ObjectSetString(0, "TrendLabel", OBJPROP_TEXT, "TREND: BEARISH ↓"); ObjectSetInteger(0, "TrendLabel", OBJPROP_COLOR, clrRed); } else { ObjectSetString(0, "TrendLabel", OBJPROP_TEXT, "TREND: RANGING"); ObjectSetInteger(0, "TrendLabel", OBJPROP_COLOR, clrYellow); } ObjectSetInteger(0, "TrendLabel", OBJPROP_FONTSIZE, 12); } //+------------------------------------------------------------------+ bool TrendReversed() { if(Previous_Trend_Bullish && Current_Trend_Bearish) { Print("===== TREND REVERSAL: BULL → BEAR ====="); return true; } if(Previous_Trend_Bearish && Current_Trend_Bullish) { Print("===== TREND REVERSAL: BEAR → BULL ====="); return true; } return false; } //+------------------------------------------------------------------+ void CloseOppositeTrades(bool close_buys) { int closed = 0; 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; ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); if((close_buys && type == POSITION_TYPE_BUY) || (!close_buys && type == POSITION_TYPE_SELL)) { Trade.PositionClose(ticket); closed++; } } if(closed > 0) Print("Closed ", closed, " opposite trades on reversal"); } //+------------------------------------------------------------------+ int CountMA7Crosses(bool check_bullish) { int crosses = 0; for(int i=1; i<6; i++) { if(check_bullish && MA_Current[0] > MA_Current[i]) crosses++; else if(!check_bullish && MA_Current[0] < MA_Current[i]) crosses++; } return crosses; } //+------------------------------------------------------------------+ bool IsPriceAtHigherMA(double price, int &ma_index, string &ma_name) { double buffer = MA_Touch_Buffer * _Point; int higher_mas[4] = {3, 4, 5, 6}; string ma_names[4] = {"MA 50", "MA 140", "MA 230", "MA 500"}; for(int i=0; i<4; i++) { int idx = higher_mas[i]; if(MathAbs(price - MA_Current[idx]) <= buffer) { ma_index = idx; ma_name = ma_names[i]; return true; } } return false; } //+------------------------------------------------------------------+ bool StochConfirms(bool check_bullish) { if(!Use_Stoch_Confirmation) return true; if(check_bullish) return (Stoch_K_Current < 70 && Stoch_K_Current >= Stoch_K_Previous); else return (Stoch_K_Current > 30 && Stoch_K_Current <= Stoch_K_Previous); } //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ 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, string reason) { double sl, tp; CalculateDynamicSLTP(price, buy, sl, tp); int sl_points = (int)(MathAbs(price - sl) / _Point); double lot = GetLotSize(sl_points); if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return; string comment = (buy ? "BULL" : "BEAR") + " | " + reason; bool result = buy ? Trade.Buy(lot, _Symbol, price, sl, tp, comment) : Trade.Sell(lot, _Symbol, price, sl, tp, 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].sl_level = sl; OpenPositions[size].tp_level = tp; OpenPositions[size].original_lot = lot; OpenPositions[size].is_buy = buy; OpenPositions[size].be_set = false; OpenPositions[size].partials_closed = 0; Print("========== TRADE ", TodayTrades, " =========="); Print(buy ? "BUY" : "SELL", " @ ", price); Print("Reason: ", reason); Print("==================================="); 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= Move_BE_At_Points) { if((is_buy && sl < entry) || (!is_buy && sl > entry)) { Trade.PositionModify(ticket, entry, 0); OpenPositions[idx].be_set = true; Print("BE SET: ", ticket, " @ ", entry); } } // 25% Partial TPs at MA 50, 140, 230, 500 double lot = PositionGetDouble(POSITION_VOLUME); // Check if at MA levels and close 25% int ma_hit_idx = -1; string ma_hit_name = ""; if(IsPriceAtHigherMA(current, ma_hit_idx, ma_hit_name)) { if(OpenPositions[idx].partials_closed < 4) { double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Partial_TP_Percent / 100.0, 2); if(close_size > 0 && close_size <= lot) { Trade.PositionClosePartial(ticket, close_size); OpenPositions[idx].partials_closed++; Print("PARTIAL TP ", OpenPositions[idx].partials_closed, ": ", ma_hit_name, " | Closed ", Partial_TP_Percent, "%"); } } } // Trailing SL by 500 points if(profit_points >= Trailing_SL_Points + 100) { double newSL = is_buy ? current - Trailing_SL_Points * _Point : current + Trailing_SL_Points * _Point; if((is_buy && newSL > sl + 50 * _Point) || (!is_buy && newSL < sl - 50 * _Point)) { Trade.PositionModify(ticket, newSL, 0); } } } } //+------------------------------------------------------------------+ void OnTick() { if(TimeCurrent() - Last_Trend_Check >= 5) { DetermineTrendBias(); if(TrendReversed()) { if(Current_Trend_Bullish) CloseOppositeTrades(false); // Close sells else if(Current_Trend_Bearish) CloseOppositeTrades(true); // Close buys } Last_Trend_Check = TimeCurrent(); } ManagePositions(); if(!CheckLimits()) return; int buy_count = 0; int sell_count = 0; for(int i=0; i= Max_Simultaneous_Trades) return; bool force_entry = (total_open < Min_Active_Entries); static datetime last_calc = 0; if(TimeCurrent() - last_calc > 1800) { CalculatePriceLevels(); if(Show_Levels) DrawLevels(); last_calc = TimeCurrent(); } UpdateMAs(); UpdateStochastic(); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double current = (bid + ask) / 2; int ma7_crosses_bull = CountMA7Crosses(true); int ma7_crosses_bear = CountMA7Crosses(false); int higher_ma_idx = -1; string ma_name = ""; bool at_higher_ma = IsPriceAtHigherMA(current, higher_ma_idx, ma_name); // BUY ONLY IF BULLISH if(Current_Trend_Bullish || force_entry) { bool buy_signal = false; string buy_reason = ""; if(ma7_crosses_bull >= Min_MA7_Crosses && StochConfirms(true)) { buy_signal = true; buy_reason = "MA7 " + IntegerToString(ma7_crosses_bull) + "x + Stoch"; } if(at_higher_ma && ma7_crosses_bull >= 1 && StochConfirms(true)) { buy_signal = true; buy_reason = ma_name + " TOUCH"; } if(force_entry && ma7_crosses_bull >= 1 && buy_count < sell_count) { buy_signal = true; buy_reason = "FORCE (" + IntegerToString(total_open) + "/" + IntegerToString(Min_Active_Entries) + ")"; } if(buy_signal) OpenTrade(true, ask, buy_reason); } // SELL ONLY IF BEARISH if(Current_Trend_Bearish || force_entry) { bool sell_signal = false; string sell_reason = ""; if(ma7_crosses_bear >= Min_MA7_Crosses && StochConfirms(false)) { sell_signal = true; sell_reason = "MA7 " + IntegerToString(ma7_crosses_bear) + "x + Stoch"; } if(at_higher_ma && ma7_crosses_bear >= 1 && StochConfirms(false)) { sell_signal = true; sell_reason = ma_name + " TOUCH"; } if(force_entry && ma7_crosses_bear >= 1 && sell_count < buy_count) { sell_signal = true; sell_reason = "FORCE (" + IntegerToString(total_open) + "/" + IntegerToString(Min_Active_Entries) + ")"; } if(sell_signal) OpenTrade(false, bid, sell_reason); } } //+------------------------------------------------------------------+