//+------------------------------------------------------------------+ //| cashcow.mq5 (VIZION MASTER EA - HUD + Aggressive Re-Entry) | //| - No candle objects (no lag). One HUD label top-right. | //| - Trend confirm: EMA7 cross EMA50 (lookback) + stack agree | //| - Entry core: EMA14 reclaim after confirm | //| - Aggressive: re-enter on NEW confirmations (pullbacks/retests) | //| - Close rules: trend flip OR MFIB rejection | //| - Risk: 300 points SL + trailing stop | //+------------------------------------------------------------------+ #property strict #property version "1.20" #include CTrade trade; //============================== INPUTS ============================== input ENUM_TIMEFRAMES InpTF = PERIOD_H1; // MA periods input int InpEMA7 = 7; input int InpEMA14 = 14; input int InpEMA21 = 21; input int InpEMA50 = 50; input int InpEMA140 = 140; input int InpEMA230 = 230; input int InpEMA500 = 500; input int InpEMA1400 = 1400; // Aggression input int InpBatchOrders = 4; // 4 trades per entry input double InpLotsPerOrder = 0.01; input int InpMaxBatchesPerTrendLeg = 6; // cap to avoid runaway stacking input int InpMinBarsBetweenEntries = 1; // 1 = can enter each new bar input int InpReentryCooldownBars = 0; // extra cooldown if needed (0 = off) // Confirmation logic input int InpTouchTolPoints = 35; input int InpCrossLookbackBars = 18; input bool InpRequireMicroStack = true; // 7>21>50 or 7<21<50 input bool InpEnterOn14Reclaim = true; // main entry preference input bool InpAllowReentryOn50Reclaim = true; input bool InpAllowReentryOn140Reclaim = true; input bool InpAllowReentryOn230Reclaim = true; // Risk / management input int InpSL_Points = 300; input bool InpUseTrailingStop = true; input int InpTrailStartPoints = 250; input int InpTrailDistancePoints = 200; input bool InpCloseOppOnTrendFlip = true; // MFIB input bool InpUseMFIBBiasFilter = true; input int InpMFIBLookbackBars = 2500; input bool InpUseCloseForMFIBBreaks = true; // HUD input bool InpShowHUD = true; //============================== COLORS ============================== color ColHud = clrWhite; //============================== HANDLES ============================= int h7=-1,h14=-1,h21=-1,h50=-1,h140=-1,h230=-1,h500=-1,h1400=-1; //============================== BUFFERS ============================= double ema7[], ema14[], ema21[], ema50[], ema140[], ema230[], ema500[], ema1400[]; MqlRates rates[]; //============================== STATE =============================== string HUD_NAME = "VIZION_HUD"; datetime g_lastBar = 0; int g_lastEntryShift = 999999; // bars since last entry datetime g_lastEntryBarTime = 0; // bar time of last entry int g_batchesThisLeg = 0; // how many batches pressed in current trend leg int g_lastSetupId = 0; // prevents duplicates (same setup repeated) int g_lastDirection = 0; // +1 long, -1 short, 0 none //============================== UTILS =============================== bool SafeCopyBuffer(const int handle, const int buffer, const int start_pos, const int count, double &arr[]) { if(handle <= 0) return false; ArrayResize(arr, count); ArraySetAsSeries(arr, true); int copied = CopyBuffer(handle, buffer, start_pos, count, arr); if(copied <= 0) return false; if(copied < count) ArrayResize(arr, copied); return true; } void EnsureHUD() { if(!InpShowHUD) return; if(ObjectFind(0, HUD_NAME) < 0) { ObjectCreate(0, HUD_NAME, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, HUD_NAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(0, HUD_NAME, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, HUD_NAME, OBJPROP_YDISTANCE, 12); ObjectSetInteger(0, HUD_NAME, OBJPROP_FONTSIZE, 10); ObjectSetString(0, HUD_NAME, OBJPROP_FONT, "Consolas"); ObjectSetInteger(0, HUD_NAME, OBJPROP_COLOR, ColHud); } } void SetHUD(const string txt) { if(!InpShowHUD) return; EnsureHUD(); ObjectSetString(0, HUD_NAME, OBJPROP_TEXT, txt); } int CountPositionsByType(const ENUM_POSITION_TYPE type) { int n = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket == 0) continue; if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; ENUM_POSITION_TYPE t = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); if(t == type) n++; } return n; } void CloseAllType(const ENUM_POSITION_TYPE type, const string reason) { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket == 0) continue; if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; ENUM_POSITION_TYPE t = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); if(t != type) continue; trade.PositionClose(ticket); Print("Closed ", (type == POSITION_TYPE_BUY ? "BUY" : "SELL"), " due to: ", reason); } } void ApplyTrailing() { if(!InpUseTrailingStop) return; double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket == 0) continue; if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); double profitPts = 0; if(type == POSITION_TYPE_BUY) profitPts = (bid - openPrice) / _Point; if(type == POSITION_TYPE_SELL) profitPts = (openPrice - ask) / _Point; if(profitPts < InpTrailStartPoints) continue; if(type == POSITION_TYPE_BUY) { double newSL = bid - InpTrailDistancePoints * _Point; if(sl == 0.0 || newSL > sl) trade.PositionModify(_Symbol, newSL, tp); } else { double newSL = ask + InpTrailDistancePoints * _Point; if(sl == 0.0 || newSL < sl) trade.PositionModify(_Symbol, newSL, tp); } } } //============================== MFIB ================================ bool ComputeMFIB(const int shift, const int lookback, double &atl, double &ath) { int last = MathMin(shift + lookback, ArraySize(rates)-1); if(last <= shift) return false; atl = rates[shift].low; ath = rates[shift].high; for(int k=shift; k<=last; k++) { if(rates[k].low < atl) atl = rates[k].low; if(rates[k].high > ath) ath = rates[k].high; } return (ath > atl); } double FibLevel(const double atl, const double ath, const double r) { return atl + (ath - atl) * r; } int MFIBBiasState(const int shift, int &stackCount) { stackCount = 0; double atl, ath; if(!ComputeMFIB(shift, InpMFIBLookbackBars, atl, ath)) return 0; double f032 = FibLevel(atl,ath,0.32); double f050 = FibLevel(atl,ath,0.50); double f0618= FibLevel(atl,ath,0.618); double f0786= FibLevel(atl,ath,0.786); double bp = rates[shift].close; // close-based for stability if(bp > f032) { if(bp > f050) stackCount = 1; if(bp > f0618) stackCount = 2; if(bp > f0786) stackCount = 3; return (stackCount>=1 ? +1 : 0); } if(bp < f032) { if(bp < f050) stackCount = 1; if(bp < f0618) stackCount = 2; if(bp < f0786) stackCount = 3; return (stackCount>=1 ? -1 : 0); } return 0; } bool MFIBRejectHigh(const int shift, double &whichLevel) { whichLevel = 0.0; double atl, ath; if(!ComputeMFIB(shift, InpMFIBLookbackBars, atl, ath)) return false; double f0618= FibLevel(atl,ath,0.618); double f0786= FibLevel(atl,ath,0.786); if(rates[shift].high >= f0786 && rates[shift].close < f0786) { whichLevel = 0.786; return true; } if(rates[shift].high >= f0618 && rates[shift].close < f0618) { whichLevel = 0.618; return true; } return false; } bool MFIBRejectLow(const int shift, double &whichLevel) { whichLevel = 0.0; double atl, ath; if(!ComputeMFIB(shift, InpMFIBLookbackBars, atl, ath)) return false; double f0618= FibLevel(atl,ath,0.618); double f0786= FibLevel(atl,ath,0.786); if(rates[shift].low <= f0786 && rates[shift].close > f0786) { whichLevel = 0.786; return true; } if(rates[shift].low <= f0618 && rates[shift].close > f0618) { whichLevel = 0.618; return true; } return false; } //============================== TREND =============================== bool CrossUp7_50(const int shift) { if(shift+1 >= ArraySize(ema7) || shift+1 >= ArraySize(ema50)) return false; double prevDiff = ema7[shift+1] - ema50[shift+1]; double currDiff = ema7[shift] - ema50[shift]; return (prevDiff <= 0.0 && currDiff > 0.0); } bool CrossDn7_50(const int shift) { if(shift+1 >= ArraySize(ema7) || shift+1 >= ArraySize(ema50)) return false; double prevDiff = ema7[shift+1] - ema50[shift+1]; double currDiff = ema7[shift] - ema50[shift]; return (prevDiff >= 0.0 && currDiff < 0.0); } bool CrossedWithin(const int shift, const int lookback, const bool bull) { int maxShift = MathMin(shift + lookback, ArraySize(ema7) - 2); for(int k=shift; k<=maxShift; k++) { if(bull && CrossUp7_50(k)) return true; if(!bull && CrossDn7_50(k)) return true; } return false; } bool StackLong(const int shift) { return (ema7[shift] > ema21[shift] && ema21[shift] > ema50[shift]); } bool StackShort(const int shift) { return (ema7[shift] < ema21[shift] && ema21[shift] < ema50[shift]); } bool TouchReclaimMA_Long(const int shift, const double ma) { double tol = InpTouchTolPoints * _Point; return (rates[shift].low <= ma + tol && rates[shift].close > ma); } bool TouchReclaimMA_Short(const int shift, const double ma) { double tol = InpTouchTolPoints * _Point; return (rates[shift].high >= ma - tol && rates[shift].close < ma); } //============================== ORDERS ============================== void PlaceBatch(const bool isBuy) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double entry = isBuy ? ask : bid; double sl = isBuy ? entry - InpSL_Points * _Point : entry + InpSL_Points * _Point; trade.SetDeviationInPoints(30); for(int k=0; k 0) { CloseAllType(POSITION_TYPE_SELL, "TREND FLIP BULL (7>50)"); g_batchesThisLeg = 0; g_lastSetupId = SETUP_NONE; g_lastDirection = 0; } if(flipBear && CountPositionsByType(POSITION_TYPE_BUY) > 0) { CloseAllType(POSITION_TYPE_BUY, "TREND FLIP BEAR (7<50)"); g_batchesThisLeg = 0; g_lastSetupId = SETUP_NONE; g_lastDirection = 0; } } // MFIB rejection closes double rej=0.0; if(CountPositionsByType(POSITION_TYPE_BUY) > 0 && MFIBRejectHigh(i, rej)) { CloseAllType(POSITION_TYPE_BUY, "MFIB REJECT HIGH @ "+DoubleToString(rej,3)); g_batchesThisLeg = 0; g_lastSetupId = SETUP_NONE; g_lastDirection = 0; } if(CountPositionsByType(POSITION_TYPE_SELL) > 0 && MFIBRejectLow(i, rej)) { CloseAllType(POSITION_TYPE_SELL, "MFIB REJECT LOW @ "+DoubleToString(rej,3)); g_batchesThisLeg = 0; g_lastSetupId = SETUP_NONE; g_lastDirection = 0; } //======================== // 2) Trend permission //======================== bool longPerm = CrossedWithin(i, InpCrossLookbackBars, true); bool shortPerm = CrossedWithin(i, InpCrossLookbackBars, false); if(InpRequireMicroStack) { longPerm = longPerm && StackLong(i); shortPerm = shortPerm && StackShort(i); } // MFIB bias permission int stackCount=0; int mfibBias = MFIBBiasState(i, stackCount); if(InpUseMFIBBiasFilter) { if(longPerm && !(mfibBias > 0 && stackCount >= 1)) longPerm = false; if(shortPerm && !(mfibBias < 0 && stackCount >= 1)) shortPerm = false; } //======================== // 3) Aggressive re-entry gating //======================== // time-based gate if(g_lastEntryBarTime != 0) { int barsSince = 0; // compute bars since last entry using bar times (simple) for(int k=1; k 0 && barsSince < InpReentryCooldownBars) { SetHUD("Reentry cooldown"); return; } } // batch cap per leg if(g_batchesThisLeg >= InpMaxBatchesPerTrendLeg) { SetHUD("Max batches reached for this trend leg"); return; } //======================== // 4) Setup detection (pick ONE best setup per bar) //======================== int setupId = SETUP_NONE; int dir = 0; string setupName = "NONE"; // Primary entry on EMA14 reclaim after confirm if(longPerm && InpEnterOn14Reclaim && TouchReclaimMA_Long(i, ema14[i])) { setupId = SETUP_ENTRY_14; dir = +1; setupName = "ENTRY_14_RECLAIM"; } else if(shortPerm && InpEnterOn14Reclaim && TouchReclaimMA_Short(i, ema14[i])) { setupId = SETUP_ENTRY_14; dir = -1; setupName = "ENTRY_14_RECLAIM"; } // Aggressive continuation re-entries (only if trend confirmed) else if(InpAllowReentryOn50Reclaim && longPerm && TouchReclaimMA_Long(i, ema50[i])) { setupId = SETUP_REENTRY_50; dir = +1; setupName = "REENTRY_50_RECLAIM"; } else if(InpAllowReentryOn50Reclaim && shortPerm && TouchReclaimMA_Short(i, ema50[i])) { setupId = SETUP_REENTRY_50; dir = -1; setupName = "REENTRY_50_RECLAIM"; } else if(InpAllowReentryOn140Reclaim && longPerm && TouchReclaimMA_Long(i, ema140[i])) { setupId = SETUP_REENTRY_140; dir = +1; setupName = "REENTRY_140_RECLAIM"; } else if(InpAllowReentryOn140Reclaim && shortPerm && TouchReclaimMA_Short(i, ema140[i])) { setupId = SETUP_REENTRY_140; dir = -1; setupName = "REENTRY_140_RECLAIM"; } else if(InpAllowReentryOn230Reclaim && longPerm && TouchReclaimMA_Long(i, ema230[i])) { setupId = SETUP_REENTRY_230; dir = +1; setupName = "REENTRY_230_RECLAIM"; } else if(InpAllowReentryOn230Reclaim && shortPerm && TouchReclaimMA_Short(i, ema230[i])) { setupId = SETUP_REENTRY_230; dir = -1; setupName = "REENTRY_230_RECLAIM"; } // Duplicate prevention: same setup twice in a row, same direction → skip if(setupId != SETUP_NONE) { if(g_lastSetupId == setupId && g_lastDirection == dir) { SetHUD("Duplicate setup blocked: " + setupName); return; } } //======================== // 5) Execute //======================== if(setupId != SETUP_NONE) { // If we already have opposite positions (should be rare due to flip close), clean them. if(dir > 0 && CountPositionsByType(POSITION_TYPE_SELL) > 0 && InpCloseOppOnTrendFlip) CloseAllType(POSITION_TYPE_SELL, "Opposite cleanup before LONG"); if(dir < 0 && CountPositionsByType(POSITION_TYPE_BUY) > 0 && InpCloseOppOnTrendFlip) CloseAllType(POSITION_TYPE_BUY, "Opposite cleanup before SHORT"); PlaceBatch(dir > 0); g_lastEntryBarTime = rates[i].time; g_batchesThisLeg++; g_lastSetupId = setupId; g_lastDirection = dir; } //======================== // 6) HUD update //======================== string biasTxt = (mfibBias>0 ? "MFIB_BULL" : (mfibBias<0 ? "MFIB_BEAR" : "MFIB_NEUTRAL")); string permTxt = (longPerm ? "LONG_OK" : (shortPerm ? "SHORT_OK" : "NO_PERM")); string hud = "VIZION CASHCOW\n" "TF: " + EnumToString(InpTF) + "\n" "Perm: " + permTxt + "\n" "MFIB: " + biasTxt + " | Stack:" + IntegerToString(stackCount) + "\n" "Setup: " + setupName + "\n" "BatchesThisLeg: " + IntegerToString(g_batchesThisLeg) + "/" + IntegerToString(InpMaxBatchesPerTrendLeg); SetHUD(hud); } //+------------------------------------------------------------------+