//+------------------------------------------------------------------+
//| Rubcn_SignalTrader.mq4 |
//| EA: prekiauja pagal "Rubcn" indikatoriaus rodykles (RC-Arw*) |
//| Nereikalauja jokių DLL. |
//+------------------------------------------------------------------+
#property strict
// ===== Parametrai
input double Lots = 0.10; // Fiksuotas lotas (naudojamas, jei RiskPercent=0)
input double RiskPercent = 0.0; // Rizika % nuo balanso vienai pozicijai (0 = nenaudoti)
input int SlippagePoints = 20; // Leistinas praslydimas (points)
input int StopLossPips = 0; // Fiksuotas SL pipsais (0 = nenaudoti)
input int TakeProfitPips = 0; // Fiksuotas TP pipsais (0 = nenaudoti)
input int TrailStopPips = 0; // Trailing stop pipsais (0 = nenaudoti)
input bool UseATRforSLTP = true; // Jei nenurodyti SL/TP – naudoti ATR daugiklius
input int ATR_Period = 10; // ATR periodas
input double SL_ATR_Mult = 2.0; // SL = ATR * daugiklis
input double TP_ATR_Mult = 4.0; // TP = ATR * daugiklis
input bool OneTradePerSymbol = true; // Viena pozicija simboliui
input bool ReverseOnSignal = true; // Apversti poziciją priešingai rodyklei
input bool OpenOnAttach = true; // Atidaryti pagal naujausią rodyklę uždėjus EA
input int MaxSignalAgeBars = 2; // Maks. rodyklės senumas (barais)
input string ArrowPrefix = "RC-Arw"; // Indikatoriaus rodyklių pavadinimų prefiksas
input bool PrintDebug = false; // Debug pranešimai
input int Magic = 20251016;
// ===== Vidaus
struct SSeen { string name; };
SSeen seen[]; // Apdorotų objektų sąrašas (sesijai)
bool didAttachCheck = false;
// ===== Pagalba
void Log(string s){ if(PrintDebug) Print(s); }
double PipPoint(){
if(Digits == 3 || Digits == 5) return 10*Point;
return Point;
}
double PriceFromPips(int pips){ return pips * PipPoint(); }
bool HaveOpenPosition(int &ticketOut, int &typeOut){
ticketOut = -1; typeOut = -1;
for(int i=OrdersTotal()-1;i>=0;i--){
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderMagicNumber()!=Magic) continue;
int t=OrderType();
if(t==OP_BUY || t==OP_SELL){ ticketOut=OrderTicket(); typeOut=t; return true; }
}
return false;
}
double LastATR(){ return iATR(Symbol(), Period(), ATR_Period, 1); }
void ComputeSLTPPoints(int direction, double &slPoints, double &tpPoints){
slPoints = 0; tpPoints = 0;
if(StopLossPips > 0) slPoints = PriceFromPips(StopLossPips)/Point;
if(TakeProfitPips > 0) tpPoints = PriceFromPips(TakeProfitPips)/Point;
if(UseATRforSLTP && (slPoints<=0 || tpPoints<=0)){
double atr = LastATR();
if(slPoints<=0 && SL_ATR_Mult>0) slPoints = (SL_ATR_Mult*atr)/Point;
if(tpPoints<=0 && TP_ATR_Mult>0) tpPoints = (TP_ATR_Mult*atr)/Point;
}
}
double AccountRiskLots(double stopDistancePoints){
if(RiskPercent<=0.0 || stopDistancePoints<=0.0) return Lots;
double riskMoney = AccountBalance()*(RiskPercent/100.0);
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE); if(tickSize<=0) tickSize=Point;
double ticksToSL = stopDistancePoints*Point/tickSize; if(ticksToSL<=0) return Lots;
double lots = riskMoney/(ticksToSL*tickValue);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP); if(lotStep<=0) lotStep=0.01;
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
lots = MathFloor(lots/lotStep)*lotStep;
lots = MathMax(minLot, MathMin(lots, maxLot));
return lots;
}
bool CloseTicket(int ticket){
if(!OrderSelect(ticket, SELECT_BY_TICKET)) return false;
int type = OrderType();
double prc = (type==OP_BUY)? Bid : Ask;
bool ok = OrderClose(ticket, OrderLots(), prc, SlippagePoints, clrNONE);
if(!ok) Print("Nepavyko uždaryti #",ticket,", klaida: ",GetLastError());
return ok;
}
bool OpenOrder(int direction, double slPoints, double tpPoints){
int type = (direction>0)? OP_BUY:OP_SELL;
double prc = (type==OP_BUY)? Ask:Bid;
double lots = (RiskPercent>0.0 && slPoints>0.0) ? AccountRiskLots(slPoints) : Lots;
double sl=0, tp=0;
if(slPoints>0) sl = (type==OP_BUY)? prc - slPoints*Point : prc + slPoints*Point;
if(tpPoints>0) tp = (type==OP_BUY)? prc + tpPoints*Point : prc - tpPoints*Point;
if(sl>0) sl = NormalizeDouble(sl, Digits);
if(tp>0) tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), type, lots, prc, SlippagePoints, sl, tp, "Rubcn EA", Magic, 0, clrNONE);
if(ticket<0){ Print("Nepavyko atidaryti orderio: ",GetLastError()); return false; }
return true;
}
void MaybeTrailStop(){
if(TrailStopPips<=0) return;
int t, type; if(!HaveOpenPosition(t,type)) return;
if(!OrderSelect(t, SELECT_BY_TICKET)) return;
double trail = PriceFromPips(TrailStopPips);
if(type==OP_BUY){
double newSL = NormalizeDouble(Bid - trail, Digits);
if(OrderStopLoss()<newSL) OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
} else {
double newSL = NormalizeDouble(Ask + trail, Digits);
if(OrderStopLoss()==0 || OrderStopLoss()>newSL) OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
// Patikrina ar objektas jau apdorotas
bool IsSeen(string name){
for(int i=0;i<ArraySize(seen);i++) if(seen.name==name) return true;
return false;
}
void MarkSeen(string name){
int n = ArraySize(seen);
ArrayResize(seen, n+1);
seen[n].name = name;
}
// Ištraukia rodyklės informaciją
bool GetArrowInfo(string objName, int &dir, datetime &t, double &price, int &shift){
jei (StringSubstr(objName,0,StringLen(ArrowPrefix))!=ArrowPrefix) grąžina klaidingą reikšmę;
jei (ObjectFind(0, objName)<0) grąžina false;
// Laikas/ kaina
t = (data/laikas) ObjectGet(objName, OBJPROP_TIME1);
kaina = ObjectGet(objName, OBJPROP_PRICE1);
// Rodyklės kodas: 233 = PIRKTI, 234 = PARDUOTI (pagal tavo indikatoriuje CreateArrow)
sveikasis_kodas = (sveikasis_kodas)ObjectGet(objName, OBJPROP_ARROWCODE);
jei (kodas ==233) katalogas = +1;
kitaip, jei (kodas ==234) dir = -1;
kitaip grąžina klaidingą;
poslinkis = iBarShift(Simbolis(), Periodas(), t, tiesa);
grąžinti teisinga;
}
// Prekybos logika pagal naujas rodykles
void ProcessSignals(bool onlyFresh){
sveikasis_suma = Objektų_suma(0, 0, -1);
for(int i=0;i<total;i++){
eilutės pavadinimas = ObjektoPavadinimas(0, i);
jei (StringSubstr(pavadinimas,0,StringLen(ArrowPrefix))!=ArrowPrefix) tęsti;
jei (IsSeen(vardas)) tęsti;
int dir, shift; datos ir laiko reikšmės tt; dvigubas pr;
jei (!GetArrowInfo(pavadinimas, katalogas, TT, pr, pamaina)) tęsti;
// Tik šviežios (pagal MaxSignalAgeBars)
jei (onlyFresh && (shift<0 || shift>MaxSignalAgeBars)) { MarkSeen(pavadinimas); tęsti; }
// Pozicijų valdymas
int t, tipas; bool hasPos = HaveOpenPosition(t, tipas);
double slPoints,tpPoints; ComputeSLTPPoints(dir,slPoints,tpPoints);
jei (turi poziciją) {
bool priešinga = (tipas==OP_BUY && katalogas<0) || (tipas==OP_SELL && katalogas>0);
jei (priešinga && AtvirkštinisSignalas) {
Log(StringFormat("Apverčiam pagal %s", pavadinimas));
UždarytiBilietą(t);
OpenOrder(katalogas, slTaškai, tpTaškai);
} dar {
Log(StringFormat("Signalas %s, bet pozicija jau yra.", pavadinimas));
}
} dar {
Log(StringFormat("Atidarom pagal %s", pavadinimas));
OpenOrder(katalogas, slTaškai, tpTaškai);
}
MarkSeen(vardas);
}
}
// ===== MT4 įvykiai
int Įjungti(){
Log("Rubcn_SignalTrader inicijuotas.");
// Jei labai nauja rodyklė – galima yra pagal ją
jei (OpenOnAttach) ProcessSignals (true);
return(INIT_SUCCEEEDED);
}
void OnDeinit(const int priežastis) {
Log("Rubcn_SignalTrader sustabdytas.");
}
void OnTick(){
// Apdorojame visas naujas rodykles, bet tik šviežias
Proceso signalai (true);
GalbūtTrailStop();
}
// Papildomai – kartą per barą „pasivyti“, jei rodyklė atsirado, kai EA buvo offline
int ĮjungtiApskaičiuoti(){ return(0); }