Vizion-Trading-EA/Experts/chtgpttrade.mq5

469 lines
30 KiB
MQL5
Raw Permalink Normal View History

<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| AggressiveMA_Retest_TP4000.mq5 |
//| MA7 crosses >=2 MAs = trend; re-enter on MA retests; |
//| TP >= 4000 points + MA "magnet" partial TPs + Stochastic confirm |
//+------------------------------------------------------------------+
#property strict
#include <Trade/Trade.mqh>
CTrade Trade;
// -------------------- INPUTS --------------------
input ulong MagicNumber = 777001;
input double Lots = 0.01;
input int SlippagePoints = 50;
// MAs
input int MA_7 = 7;
input int MA_14 = 14;
input int MA_21 = 21;
input int MA_50 = 50;
input int MA_140 = 140;
input int MA_230 = 230;
input int MA_1000= 1000;
input int MA_1100= 1100;
input int MA_1300= 1300;
input ENUM_MA_METHOD MA_Method = MODE_EMA;
input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE;
// Entry aggressiveness
input int RetestBufferPoints = 250; // how close price must get to MA to count as "retest"
input int CooldownBarsPerEntry = 1; // prevent same-bar spam entries
// Stochastic confirm (instead of TRIX)
input int StochK = 5;
input int StochD = 3;
input int StochSlowing = 3;
input ENUM_MA_METHOD StochMethod = MODE_SMA;
input ENUM_STO_PRICE StochPrice = STO_LOWHIGH;
// Stoch quarter theory levels
input double StochLvl_1 = 25.0;
input double StochLvl_2 = 50.0;
input double StochLvl_3 = 75.0;
// PROFIT TAKING (what you asked for)
input int TP_MinPoints = 4000; // hard TP distance from entry (server-side)
input int BE_TriggerPoints = 4000; // optional: move SL to BE after this (set 0 to disable)
input int BE_LockPoints = 200; // lock a little profit after BE trigger
// Partial TP at profit thresholds (in addition to MA magnets)
input bool UseProfitPartials = true;
input int PT1_Points = 4000;
input double PT1_ClosePct = 0.35; // close 35% at +4000 points
input int PT2_Points = 8000;
input double PT2_ClosePct = 0.35; // close 35% at +8000 points
input int PT3_Points = 12000;
input double PT3_ClosePct = 0.30; // close remaining at +12000 points (or let TP handle it)
// MA Magnet partials
input bool UseMAMagnets = true;
input int MagnetBufferPoints = 250; // distance to MA to count as "hit"
input double MagnetClosePct = 0.20; // close 20% each time a new MA magnet is hit
// -------------------- HANDLES --------------------
int hMA7=-1,hMA14=-1,hMA21=-1,hMA50=-1,hMA140=-1,hMA230=-1,hMA1000=-1,hMA1100=-1,hMA1300=-1;
int hStoch=-1;
// -------------------- STATE --------------------
datetime lastEntryBarTime=0;
// -------------------- HELPERS --------------------
double MidPrice()
{
double b=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double a=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
if(b<=0 || a<=0) return 0;
return 0.5*(a+b);
}
bool Copy1(int handle, int shift, double &out)
{
double buf[];
ArraySetAsSeries(buf,true);
if(CopyBuffer(handle,0,shift,1,buf)!=1) return false;
out = buf[0];
return true;
}
bool CopyStoch(int shift, double &k, double &d)
{
double bk[], bd[];
ArraySetAsSeries(bk,true);
ArraySetAsSeries(bd,true);
// Stoch main is buffer 0, signal is buffer 1 in MQL5
if(CopyBuffer(hStoch,0,shift,1,bk)!=1) return false;
if(CopyBuffer(hStoch,1,shift,1,bd)!=1) return false;
k=bk[0]; d=bd[0];
return true;
}
bool GetMAValues(int shift,
double &ma7,double &ma14,double &ma21,double &ma50,double &ma140,double &ma230,
double &ma1000,double &ma1100,double &ma1300)
{
if(!Copy1(hMA7,shift,ma7)) return false;
if(!Copy1(hMA14,shift,ma14)) return false;
if(!Copy1(hMA21,shift,ma21)) return false;
if(!Copy1(hMA50,shift,ma50)) return false;
if(!Copy1(hMA140,shift,ma140)) return false;
if(!Copy1(hMA230,shift,ma230)) return false;
if(!Copy1(hMA1000,shift,ma1000)) return false;
if(!Copy1(hMA1100,shift,ma1100)) return false;
if(!Copy1(hMA1300,shift,ma1300)) return false;
return true;
}
// Trend direction:
// +1 bullish if MA7 above BOTH MA14 & MA21 (and preferably above others)
// -1 bearish if MA7 below BOTH MA14 & MA21
int TrendDir(int shift, int &strengthOut)
{
strengthOut=0;
double ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300;
if(!GetMAValues(shift,ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300))
return 0;
double others[7] = {ma14,ma21,ma50,ma140,ma230,ma1000,ma1100};
int above=0, below=0;
for(int i=0;i<7;i++)
{
if(ma7 > others[i]) above++;
if(ma7 < others[i]) below++;
}
bool bullConfirmed = (ma7 > ma14 && ma7 > ma21 && above>=2);
bool bearConfirmed = (ma7 < ma14 && ma7 < ma21 && below>=2);
if(bullConfirmed){ strengthOut=above; return +1; }
if(bearConfirmed){ strengthOut=below; return -1; }
return 0;
}
bool IsNewBar()
{
datetime t=iTime(_Symbol,PERIOD_CURRENT,0);
static datetime prev=0;
if(t!=prev){ prev=t; return true; }
return false;
}
bool InCooldown()
{
datetime t=iTime(_Symbol,PERIOD_CURRENT,0);
if(t==lastEntryBarTime) return true;
return false;
}
int CountMyPositions()
{
int c=0;
int total=(int)PositionsTotal();
for(int i=0;i<total;i++)
{
ulong ticket=PositionGetTicket(i);
if(ticket==0) continue;
if(!PositionSelectByTicket(ticket)) continue;
if((ulong)PositionGetInteger(POSITION_MAGIC)!=MagicNumber) continue;
if(PositionGetString(POSITION_SYMBOL)!=_Symbol) continue;
c++;
}
return c;
}
double ProfitPointsForPosition()
{
// assumes PositionSelectByTicket already done
long type = PositionGetInteger(POSITION_TYPE);
double open=PositionGetDouble(POSITION_PRICE_OPEN);
double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
if(type==POSITION_TYPE_BUY)
return (bid-open)/_Point;
else
return (open-ask)/_Point;
}
bool PriceNear(double price, double level, int bufferPoints)
{
return (MathAbs(price-level) <= bufferPoints*_Point);
}
// One-time trigger key for magnet hits
string MagnetKey(ulong ticket, int maPeriod)
{
return "MAG_"+_Symbol+"_"+(string)MagicNumber+"_"+(string)ticket+"_"+(string)maPeriod;
}
// Close partial safely
bool ClosePartial(ulong ticket, double closePct)
{
if(closePct<=0) return false;
if(!PositionSelectByTicket(ticket)) return false;
double vol=PositionGetDouble(POSITION_VOLUME);
double minv=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
double step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
double closeVol = vol * closePct;
// normalize to step
closeVol = MathFloor(closeVol/step)*step;
if(closeVol < minv) return false;
if(closeVol > vol) closeVol = vol;
Trade.SetDeviationInPoints(SlippagePoints);
return Trade.PositionClosePartial(ticket, closeVol);
}
void MoveSLToBE(ulong ticket, int lockPoints)
{
if(!PositionSelectByTicket(ticket)) return;
long type = PositionGetInteger(POSITION_TYPE);
double open=PositionGetDouble(POSITION_PRICE_OPEN);
double sl =PositionGetDouble(POSITION_SL);
double tp =PositionGetDouble(POSITION_TP);
double newSL=sl;
if(type==POSITION_TYPE_BUY)
newSL = open + lockPoints*_Point;
else
newSL = open - lockPoints*_Point;
// only improve SL
if(type==POSITION_TYPE_BUY && (sl<=0 || newSL>sl))
Trade.PositionModify(ticket,newSL,tp);
if(type==POSITION_TYPE_SELL && (sl<=0 || newSL<sl))
Trade.PositionModify(ticket,newSL,tp);
}
// Stochastic quarter confirmation:
// bullish bias if K > 50, stronger if > 75
// bearish bias if K < 50, stronger if < 25
bool StochConfirms(int dir, int shift)
{
double k,d;
if(!CopyStoch(shift,k,d)) return true; // if no data, don't block trades
if(dir>0)
return (k >= StochLvl_2); // >=50
if(dir<0)
return (k <= StochLvl_2); // <=50
return false;
}
// Entry trigger:
// 1) TrendDir says bull/bear (MA7 crossed 2+ MAs)
// 2) price retests MA7 or any crossed MA (we ll prioritize MA7 retest)
// 3) stochastic confirms
bool EntrySignal(int &dirOut)
{
int strength=0;
int dir = TrendDir(1,strength);
if(dir==0) return false;
if(!StochConfirms(dir,1)) return false;
double ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300;
if(!GetMAValues(0,ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300))
return false;
double price = MidPrice();
if(price<=0) return false;
// aggressive: any retest near MA7 OR near any MA that MA7 is on the  trend side of
bool near7 = PriceNear(price, ma7, RetestBufferPoints);
//  crossed MAs are those that MA7 is above (bull) or below (bear)
bool nearOther=false;
if(dir>0)
{
if(ma7>ma14 && PriceNear(price,ma14,RetestBufferPoints)) nearOther=true;
if(ma7>ma21 && PriceNear(price,ma21,RetestBufferPoints)) nearOther=true;
if(ma7>ma50 && PriceNear(price,ma50,RetestBufferPoints)) nearOther=true;
if(ma7>ma140&& PriceNear(price,ma140,RetestBufferPoints)) nearOther=true;
if(ma7>ma230&& PriceNear(price,ma230,RetestBufferPoints)) nearOther=true;
}
else
{
if(ma7<ma14 && PriceNear(price,ma14,RetestBufferPoints)) nearOther=true;
if(ma7<ma21 && PriceNear(price,ma21,RetestBufferPoints)) nearOther=true;
if(ma7<ma50 && PriceNear(price,ma50,RetestBufferPoints)) nearOther=true;
if(ma7<ma140&& PriceNear(price,ma140,RetestBufferPoints)) nearOther=true;
if(ma7<ma230&& PriceNear(price,ma230,RetestBufferPoints)) nearOther=true;
}
if(!(near7 || nearOther)) return false;
dirOut=dir;
return true;
}
bool OpenTrade(int dir)
{
Trade.SetExpertMagicNumber((uint)MagicNumber);
Trade.SetDeviationInPoints(SlippagePoints);
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
if(ask<=0 || bid<=0) return false;
double tp=0.0;
// hard TP distance >= 4000 points
if(TP_MinPoints>0)
{
if(dir>0) tp = ask + TP_MinPoints*_Point;
else tp = bid - TP_MinPoints*_Point;
}
bool ok=false;
if(dir>0) ok = Trade.Buy(Lots,_Symbol,ask,0,tp,"MA7_retest_buy");
else ok = Trade.Sell(Lots,_Symbol,bid,0,tp,"MA7_retest_sell");
if(ok)
lastEntryBarTime = iTime(_Symbol,PERIOD_CURRENT,0);
return ok;
}
void ManagePositions()
{
int total=(int)PositionsTotal();
for(int i=0;i<total;i++)
{
ulong ticket=PositionGetTicket(i);
if(ticket==0) continue;
if(!PositionSelectByTicket(ticket)) continue;
if((ulong)PositionGetInteger(POSITION_MAGIC)!=MagicNumber) continue;
if(PositionGetString(POSITION_SYMBOL)!=_Symbol) continue;
long type = PositionGetInteger(POSITION_TYPE);
double price = (type==POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol,SYMBOL_BID)
: SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double profitPts = ProfitPointsForPosition();
if(profitPts <= 0) continue;
// ---- PROFIT PARTIALS ----
if(UseProfitPartials)
{
// Use GlobalVariables so each threshold triggers only once per ticket
string k1="PT1_"+(string)ticket, k2="PT2_"+(string)ticket, k3="PT3_"+(string)ticket;
if(PT1_Points>0 && profitPts>=PT1_Points && !GlobalVariableCheck(k1))
{
ClosePartial(ticket, PT1_ClosePct);
GlobalVariableSet(k1, TimeCurrent());
}
if(PT2_Points>0 && profitPts>=PT2_Points && !GlobalVariableCheck(k2))
{
ClosePartial(ticket, PT2_ClosePct);
GlobalVariableSet(k2, TimeCurrent());
}
if(PT3_Points>0 && profitPts>=PT3_Points && !GlobalVariableCheck(k3))
{
ClosePartial(ticket, PT3_ClosePct);
GlobalVariableSet(k3, TimeCurrent());
}
}
// ---- MOVE SL TO BE AFTER +4000 (optional) ----
if(BE_TriggerPoints>0 && profitPts>=BE_TriggerPoints)
{
string bek="BE_"+(string)ticket;
if(!GlobalVariableCheck(bek))
{
MoveSLToBE(ticket, BE_LockPoints);
GlobalVariableSet(bek, TimeCurrent());
}
}
// ---- MA MAGNET PARTIAL TPs ----
if(UseMAMagnets)
{
double ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300;
if(!GetMAValues(0,ma7,ma14,ma21,ma50,ma140,ma230,ma1000,ma1100,ma1300))
continue;
// target the "big magnets" first
struct MMag { int p; double v; };
MMag mags[6] = {
{MA_50, ma50}, {MA_140, ma140}, {MA_230, ma230},
{MA_1000, ma1000}, {MA_1100, ma1100}, {MA_1300, ma1300}
};
for(int m=0;m<6;m++)
{
string key = MagnetKey(ticket, mags[m].p);
if(GlobalVariableCheck(key)) continue;
if(PriceNear(price, mags[m].v, MagnetBufferPoints))
{
// close a chunk once per MA per ticket
ClosePartial(ticket, MagnetClosePct);
GlobalVariableSet(key, TimeCurrent());
}
}
}
}
}
// -------------------- MQL5 EVENTS --------------------
int OnInit()
{
Trade.SetExpertMagicNumber((uint)MagicNumber);
hMA7 = iMA(_Symbol,PERIOD_CURRENT,MA_7,0,MA_Method,MA_Price);
hMA14 = iMA(_Symbol,PERIOD_CURRENT,MA_14,0,MA_Method,MA_Price);
hMA21 = iMA(_Symbol,PERIOD_CURRENT,MA_21,0,MA_Method,MA_Price);
hMA50 = iMA(_Symbol,PERIOD_CURRENT,MA_50,0,MA_Method,MA_Price);
hMA140 = iMA(_Symbol,PERIOD_CURRENT,MA_140,0,MA_Method,MA_Price);
hMA230 = iMA(_Symbol,PERIOD_CURRENT,MA_230,0,MA_Method,MA_Price);
hMA1000 = iMA(_Symbol,PERIOD_CURRENT,MA_1000,0,MA_Method,MA_Price);
hMA1100 = iMA(_Symbol,PERIOD_CURRENT,MA_1100,0,MA_Method,MA_Price);
hMA1300 = iMA(_Symbol,PERIOD_CURRENT,MA_1300,0,MA_Method,MA_Price);
hStoch = iStochastic(_Symbol,PERIOD_CURRENT,StochK,StochD,StochSlowing,StochMethod,StochPrice);
if(hMA7<0 || hMA14<0 || hMA21<0 || hMA50<0 || hMA140<0 || hMA230<0 || hMA1000<0 || hMA1100<0 || hMA1300<0 || hStoch<0)
return INIT_FAILED;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(hMA7>0) IndicatorRelease(hMA7);
if(hMA14>0) IndicatorRelease(hMA14);
if(hMA21>0) IndicatorRelease(hMA21);
if(hMA50>0) IndicatorRelease(hMA50);
if(hMA140>0) IndicatorRelease(hMA140);
if(hMA230>0) IndicatorRelease(hMA230);
if(hMA1000>0) IndicatorRelease(hMA1000);
if(hMA1100>0) IndicatorRelease(hMA1100);
if(hMA1300>0) IndicatorRelease(hMA1300);
if(hStoch>0) IndicatorRelease(hStoch);
}
void OnTick()
{
// manage first (locks profit fast)
ManagePositions();
// entry logic
if(InCooldown()) return;
int dir=0;
if(EntrySignal(dir))
{
// aggressive: allow multiple positions, but you can cap if needed
OpenTrade(dir);
}
}