Update 1.3.6 .... some bug fixes and trailing stop/profit for orders stucked on block condition.
Better management of the gain.
//+------------------------------------------------------------------+
//| Charles.mq4 |
//| Copyright 2012, AlFa Corp. |
//| alessio.fabiani @ gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, AlFa"
#property link "alessio.fabiani @ gmail.com"
#define MAGICMA 3937
#define VER "1.3.6"
extern int Anchor = 250;
extern double xFactor = 1.5;
extern string TimeSet = "07:32";
extern double Amount = 1.0;
extern double RiskPercent = 5;
extern double LotPercent = 5;
extern double Lots = 0.01;
extern double StopLoss = 0;
extern double TrailingProfit = 20;
extern double TrailingStop = 50;
extern int Slippage = 2;
extern string Macd = "Quick, Slow, Signal";
extern int Qema = 10;
extern int Sema = 32;
extern int Signalmacd = 4;
extern string Ema = "fast close, slow open.";
extern int Fastema = 8;
extern int Slowema = 14;
extern bool AllOrders = false;
extern bool LogToFile = false;
int PendingBuy, PendingSell, Buys, Sells, i, Spread, STOPLEVEL;
double BuyLots, SellLots, PendingBuyLots, PendingSellLots;
double Focus, Profit, LastProfit, Up, Dw, LookingForProfit;
double stoploss,takeprofit;
double LotsValue, Denominator;
double MaxPrice,MinPrice,MaxOpenPrice,MinOpenPrice;
bool isInGain=false, blockConditionHit=false, unlockOrdersPlaced=false;
int LastOrderTicket = -1;
double lastBarTime;
//+------------------------------------------------------------------+
//| Init function |
//+------------------------------------------------------------------+
void init()
{
LookingForProfit = Amount/10.0;
if(LogToFile){startFile();}
Spread = MarketInfo(Symbol(),MODE_SPREAD);
if(AccountBalance()<1000){Denominator=400;}
else{Denominator=200;}
lastBarTime = TimeCurrent();
}
//+------------------------------------------------------------------+
//| Start function |
//+------------------------------------------------------------------+
void start()
{
int SystemPeriod = Period();
if ( (TimeCurrent() - lastBarTime) >= 2.0 )
{
Count();
if (LotPercent < 1)
{
LotsValue = Lots;
}
else
{
LotsValue = LOT();
}
int Delta=10; //Order price shift (in points) from High/Low price
int LastDay=0;
STOPLEVEL = MarketInfo(Symbol(),MODE_STOPLEVEL);
MaxPrice=iHigh(Symbol(),PERIOD_D1,LastDay)+NormalizeDouble(Delta*Point,Digits);
MinPrice=iLow(Symbol(),PERIOD_D1,LastDay)-NormalizeDouble(Delta*Point,Digits);
MaxOpenPrice=MaxPrice;
MinOpenPrice=MinPrice;
if (Ask+STOPLEVEL*Point>MaxPrice) MaxOpenPrice = NormalizeDouble(Ask+STOPLEVEL*Point,Digits);
if (Bid-STOPLEVEL*Point<MinPrice) MinOpenPrice = NormalizeDouble(Bid-STOPLEVEL*Point,Digits);
//LIMITI
Dw=Bid-Anchor*Point;
Up=Ask+Anchor*Point;
double LotsHedgeValue;
LotsHedgeValue = (LotsValue*xFactor);
LotsHedgeValue = NormalizeDouble(LotsHedgeValue, 2);
if(LotsHedgeValue < MarketInfo(Symbol(), MODE_MINLOT))
{
LotsHedgeValue = NormalizeDouble(MarketInfo(Symbol(), MODE_MINLOT)*xFactor, 2);
}
//SYSTEM CORE
if(PendingSell == 0 && PendingBuy == 0)
{
log("[PendingSellLots == 0 && PendingBuyLots == 0] OP_SELLSTOP+OP_BUYSTOP; LotsHedgeValue: " + LotsHedgeValue);
stoploss = /*Ask+SL*Point*/ 0;
takeprofit = /*Bid-TP*Point*/ 0;
OrderSend(Symbol(),OP_SELLSTOP,LotsHedgeValue,Dw,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,0,Red);
Sleep(10);
stoploss = /*Bid-SL*Point*/ 0;
takeprofit = /*Ask+TP*Point*/ 0;
OrderSend(Symbol(),OP_BUYSTOP,LotsHedgeValue,Up,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,0,Blue);
}
else
{
if((PendingSell == 0 && PendingBuy > 0) || (PendingSell > 0 && PendingBuy == 0))
{
int Result=-1;
if(PendingBuy > 0)
{
log("[PendingBuyLots > 0] OP_SELLSTOP; Dw: "+Dw+";LotsHedgeValue: "+LotsHedgeValue+"; PendingBuyLots: "+PendingBuyLots+"; PendingSellLots: "+PendingSellLots);
stoploss = /*Ask+SL*Point*/ 0;
takeprofit = /*Bid-TP*Point*/ 0;
Result=OrderSend(Symbol(),OP_SELLSTOP,LotsHedgeValue,Dw,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,0,Red);
}
else if(PendingSell > 0)
{
log("[PendingSellLots > 0] OP_BUYSTOP; Up: "+Up+";LotsHedgeValue: "+LotsHedgeValue+"; PendingBuyLots: "+PendingBuyLots+"; PendingSellLots: "+PendingSellLots);
stoploss = /*Bid-SL*Point*/ 0;
takeprofit = /*Ask+TP*Point*/ 0;
Result=OrderSend(Symbol(),OP_BUYSTOP,LotsHedgeValue,Up,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,0,Blue);
}
}
}
Count();
if(Buys==0 && Sells==0){CheckForOpen();}
else{CheckForClose();}
lastBarTime = TimeCurrent();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
int CheckForOpen()
{
int expiration=CurTime()+(23-TimeHour(CurTime()))*3600+(60-TimeMinute(CurTime()))*60; //set order expiration time
if( (PendingSell==0 && PendingBuy==0) || (TimeStr(CurTime())==TimeSet) )
{
if(PendingBuyLots==0)
{
stoploss = /*Bid-SL*Point*/ 0;
takeprofit = /*Ask+TP*Point*/ 0;
OrderSend(Symbol(),OP_BUYSTOP,LotsValue,MaxOpenPrice,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,expiration,Blue);
}
if(PendingSellLots==0)
{
stoploss = /*Ask+SL*Point*/ 0;
takeprofit = /*Bid-TP*Point*/ 0;
OrderSend(Symbol(),OP_SELLSTOP,LotsValue,MinOpenPrice,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,expiration,Red);
}
}
CharlesStatus();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
int CheckForClose()
{
RefreshRates();
if(AccountBalance()>=1000){Amount=10.0+(AccountBalance()/10000);}
else{Amount=1.0+(AccountBalance()/1000);}
//CONDIZIONE DI CHIUSURA DI SUCCESSO
if(Profit>=0 && Profit>=Amount/10)
{
log("[CONDIZIONE DI CHIUSURA DI SUCCESSO]; Profit: "+Profit+"; Amount: "+Amount+"; LastProfit: "+LastProfit);
if(!isInGain)
{
isInGain = true;
LastProfit = Profit;
LookingForProfit = Profit;
}
if(Profit<=(LastProfit - Amount/10))
{
log("[CONDIZIONE DI CHIUSURA DI SUCCESSO - CloseAll]; Profit: "+Profit+"; Amount: "+Amount+"; LastProfit: "+LastProfit);
isInGain = false;
blockConditionHit=false;
unlockOrdersPlaced=false;
LastOrderTicket = -1;
LookingForProfit = Amount/10;
CloseAll();
}
else
{
LastProfit = Profit;
LookingForProfit = Profit + Profit/10;
}
}
//CONDIZIONE DI BLOCCAGGIO E SBLOCCAGGIO DI EMERGENZA
if(Profit<-AccountBalance()*RiskPercent/100)
{
if(!blockConditionHit)
{
log("[CONDIZIONE DI BLOCCAGGIO DI EMERGENZA - First Hit]: DeleteAllPendingOrders; AccountFreeMargin: " + AccountFreeMargin());
blockConditionHit=true;
if (SellLots>BuyLots)
{
DeleteAllPendingOrders();
LastOrderTicket=OpenOrder(SellLots-BuyLots, OP_BUY);
}
else if (BuyLots>SellLots)
{
DeleteAllPendingOrders();
LastOrderTicket=OpenOrder(BuyLots-SellLots, OP_SELL);
}
}
}
if(blockConditionHit && !unlockOrdersPlaced)
{
int Current = 0;
double Ema20_1 = iMA(Symbol(), Period(), 20, 0, MODE_EMA, PRICE_CLOSE, Current + 1);
double Ema20_2 = iMA(Symbol(), Period(), 20, 0, MODE_EMA, PRICE_OPEN, Current + 0);
double Buy1_1 = iMA(Symbol(), PERIOD_H4, Fastema, 0, MODE_EMA, PRICE_CLOSE, Current + 0);
double Buy1_2 = iMA(Symbol(), PERIOD_H4, Slowema, 0, MODE_EMA, PRICE_OPEN, Current + 0);
double Buy2_1 = iMACD(Symbol(), PERIOD_H4, Qema, Sema, Signalmacd, PRICE_CLOSE, MODE_SIGNAL, Current + 1);
double Buy2_2 = iMACD(Symbol(), PERIOD_H4, Qema, Sema, Signalmacd, PRICE_CLOSE, MODE_SIGNAL, Current + 0);
double Sell1_1 = iMA(Symbol(), PERIOD_H4, Fastema, 0, MODE_EMA, PRICE_CLOSE, Current + 0);
double Sell1_2 = iMA(Symbol(), PERIOD_H4, Slowema, 0, MODE_EMA, PRICE_OPEN, Current + 0);
double Sell2_1 = iMACD(Symbol(), PERIOD_H4, Qema, Sema, Signalmacd, PRICE_CLOSE, MODE_SIGNAL, Current + 0);
double Sell2_2 = iMACD(Symbol(), PERIOD_H4, Qema, Sema, Signalmacd, PRICE_CLOSE, MODE_SIGNAL, Current + 1);
double UnlockMaxPrice=iHigh(Symbol(),PERIOD_H4,0)+NormalizeDouble(10*Point,Digits);
double UnlockMinPrice=iLow(Symbol(),PERIOD_H4,0)-NormalizeDouble(10*Point,Digits);
if (Ask+STOPLEVEL*Point>UnlockMaxPrice) UnlockMaxPrice = NormalizeDouble(Ask+STOPLEVEL*Point,Digits);
if (Bid-STOPLEVEL*Point<UnlockMinPrice) UnlockMinPrice = NormalizeDouble(Bid-STOPLEVEL*Point,Digits);
if(Buy1_1 > Buy1_2 && Buy2_1 < Buy2_2)
{
OrderSend(Symbol(),OP_BUYSTOP,LotsValue,UnlockMaxPrice,Slippage,0,0,"Charles_"+VER,MAGICMA,0,Blue);
unlockOrdersPlaced=true;
}
else if(Sell1_1 < Sell1_2 && Sell2_1 < Sell2_2)
{
OrderSend(Symbol(),OP_SELLSTOP,LotsValue,UnlockMinPrice,Slippage,0,0,"Charles_"+VER,MAGICMA,0,Red);
unlockOrdersPlaced=true;
}
//CHIUSURA ORDINI PROFITTEVOLI
TrailStop(MAGICMA);
}
CharlesStatus();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void CharlesStatus()
{
Count();
Comment("Charles ",VER," - Gain= ",/*Profit*/AccountProfit()," LookingFor= ",LookingForProfit,
";\nBalance=",AccountBalance(),"; FreeMargin=", AccountFreeMargin(),"; Equity=", AccountEquity(),
";\nBuy=",Buys,"; Sell=", Sells,"; BuyLots=",BuyLots,"; SellLots=",SellLots,
";\nPendingSellLots=",PendingSellLots,"; PendingBuyLots=", PendingBuyLots);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
double LOT()
{
RefreshRates();
double MINLOT = MarketInfo(Symbol(),MODE_MINLOT);
double LOT = AccountFreeMargin()*AccountLeverage()*RiskPercent/1000/MarketInfo(Symbol(),MODE_MARGINREQUIRED)/15;
if (LOT>MarketInfo(Symbol(),MODE_MAXLOT)) LOT = MarketInfo(Symbol(),MODE_MAXLOT);
if (LOT<MINLOT) LOT = MINLOT;
if (MINLOT<0.1) LOT = NormalizeDouble(LOT,2); else LOT = NormalizeDouble(LOT,1);
return(LOT);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void Count()
{
RefreshRates();
Buys=0; Sells=0; PendingBuy=0; PendingSell=0; BuyLots=0; SellLots=0; PendingBuyLots=0; PendingSellLots=0; Profit=0;
for(i=OrdersTotal(); i>=0; i--)
{
OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
if(OrderSymbol()==Symbol())
{
if(!AllOrders && OrderMagicNumber()!=MAGICMA)
{
continue;
}
Profit = Profit + OrderProfit() + OrderSwap();
if(OrderType()==OP_SELL){SellLots=SellLots+OrderLots();Sells++;}
if(OrderType()==OP_BUY){BuyLots=BuyLots+OrderLots();Buys++;}
if(OrderType()==OP_SELLSTOP || OrderType()==OP_SELLLIMIT){PendingSellLots=PendingSellLots+OrderLots();PendingSell++;}
if(OrderType()==OP_BUYSTOP || OrderType()==OP_BUYLIMIT){PendingBuyLots=PendingBuyLots+OrderLots();PendingBuy++;}
}//if
}//for
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void CloseAll()
{
RefreshRates();
bool Result;
int i,Pos,Error;
int Total=OrdersTotal();
if(Total>0)
{for(i=Total-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == TRUE)
{
if(OrderSymbol()==Symbol())
{
if(!AllOrders && OrderMagicNumber()!=MAGICMA)
{
continue;
}
Pos=OrderType();
if(Pos==OP_BUY){Result=OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Blue);}
if(Pos==OP_SELL){Result=OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Red);}
if((Pos==OP_BUYSTOP)||(Pos==OP_SELLSTOP)||(Pos==OP_BUYLIMIT)||(Pos==OP_SELLLIMIT)){Result=OrderDelete(OrderTicket(), CLR_NONE);}
//-----------------------
if(Result!=true){Error=GetLastError();log("LastError = "+Error);}
else Error=0;
//-----------------------
}//if
}//if
}//for
}//if
Sleep(20);
return(0);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void DeleteAllPendingOrders()
{
RefreshRates();
bool Result;
int i,Pos,Error;
int Total=OrdersTotal();
if(Total>0)
{for(i=Total-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == TRUE)
{
if(OrderSymbol()==Symbol())
{
if(!AllOrders && OrderMagicNumber()!=MAGICMA)
{
continue;
}
Pos=OrderType();
if((Pos==OP_BUYSTOP)||(Pos==OP_SELLSTOP)||(Pos==OP_BUYLIMIT)||(Pos==OP_SELLLIMIT)){Result=OrderDelete(OrderTicket(), CLR_NONE);}
//-----------------------
if(Result!=true){Error=GetLastError();log("LastError = "+Error);}
else Error=0;
//-----------------------
}//if
}//if
}//for
}//if
return(0);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
int OpenOrder(double LotOpenValue, int Type)
{
RefreshRates();
int Error, Result;
log("OpenOrder - LotHedgeValue:" + LotOpenValue + "; AccountFreeMargin: "+AccountFreeMargin());
if(AccountFreeMargin()>0)
{
log("MarketInfo(Symbol(),MODE_MARGINREQUIRED) == " + MarketInfo(Symbol(),MODE_MARGINREQUIRED));
log("Ask("+Ask+")-MaxOpenPrice("+MaxOpenPrice+") == " + (Ask-MaxOpenPrice));
log("MinOpenPrice("+MinOpenPrice+")-Bid("+Bid+") == " + (MinOpenPrice-Bid));
if(Type==OP_BUY)
{
stoploss = /*Bid-SL*Point*/ 0;
takeprofit = /*Ask+TP*Point*/ 0;
Result=OrderSend(Symbol(),OP_BUY,LotOpenValue,Ask,Slippage,stoploss,takeprofit,"Charels_"+VER,MAGICMA,0,Blue);
log("OpenOrder[OP_BUY] - Ask:" + Ask + "; Result: "+Result);
}
if(Type==OP_SELL)
{
stoploss = /*Ask+SL*Point*/ 0;
takeprofit = /*Bid-TP*Point*/ 0;
Result=OrderSend(Symbol(),OP_SELL,LotOpenValue,Bid,Slippage,stoploss,takeprofit,"Charles_"+VER,MAGICMA,0,Red);
log("OpenOrder[OP_SELL] - Bid:" + Bid + "; Result: "+Result);
}
}
//-----------------------
if(Result==-1){Error=GetLastError();log("LastError = "+Error);}
else {Error=0;}
//-----------------------
return(Result);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void TrailStop(int magic) {
for(i=OrdersTotal(); i>=0; i--)
{
OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == magic && OrderSymbol() == Symbol())
{
RefreshRates();
if (OrderType() == OP_BUY)
{
if(Bid-OrderOpenPrice()<0)
{
OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice()-Point*TrailingStop, Bid+Point*TrailingProfit, 0, Blue);
continue;
}
else if(TrailingStop>0)
{
if( Bid-Point*TrailingStop>OrderOpenPrice() )
{
if (OrderStopLoss() < Bid-Point*TrailingStop)
{OrderModify(OrderTicket(), OrderOpenPrice(), Bid-Point*TrailingStop, Bid+Point*TrailingProfit, 0, Blue);}
continue;
}
}
else if ((OrderStopLoss() != Bid - StopLoss*Point) && (StopLoss != 0))
{
OrderModify(OrderTicket(), OrderOpenPrice(), Bid-StopLoss*Point, Bid+Point*TrailingProfit, Blue);
continue;
}
}
else if (OrderType() == OP_SELL)
{
if(OrderOpenPrice()-Ask<0)
{
OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice()+Point*TrailingStop, Ask-Point*TrailingProfit, 0, Blue);
continue;
}
else if(TrailingStop>0)
{
if ( Ask+Point*TrailingStop<OrderOpenPrice() )
{
if (OrderStopLoss() > Ask+Point*TrailingStop)
{OrderModify(OrderTicket(), OrderOpenPrice(), Ask+Point*TrailingStop, Ask-Point*TrailingProfit, Red);}
continue;
}
}
else if( (OrderStopLoss() != Ask+Point*StopLoss) && (StopLoss != 0) )
{
OrderModify(OrderTicket(), OrderOpenPrice(), Ask+StopLoss*Point, Ask-Point*TrailingProfit, Red);
continue;
}
}
if( IsStopped() ) { break; }
}
}
return(0);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void startFile()
{
int handle;
handle=FileOpen("Charles-"+VER+".log", FILE_BIN|FILE_READ|FILE_WRITE);
if(handle<1)
{
Print("can't open file error-",GetLastError());
return(0);
}
FileSeek(handle, 0, SEEK_END);
//---- add data to the end of file
string str =
"----------------------------------------------------------------------------------------------------------------------------------------\n" +
"-- Charles v."+VER+" - Log Starting... --\n" +
"----------------------------------------------------------------------------------------------------------------------------------------\n";
FileWriteString(handle, str, StringLen(str));
FileFlush(handle);
FileClose(handle);
}
void log(string str)
{
str = "["+Day()+"-"+Month()+"-"+Year()+" "+Hour()+":"+Minute()+":"+Seconds()+"] "+str+"\n";
if(LogToFile)
{
int handle;
handle=FileOpen("Charles-"+VER+".log", FILE_BIN|FILE_READ|FILE_WRITE);
if(handle<1)
{
Print("can't open file error-",GetLastError());
return(0);
}
FileSeek(handle, 0, SEEK_END);
//---- add data to the end of file
FileWriteString(handle, str, StringLen(str));
FileFlush(handle);
FileClose(handle);
}
else
{
Print(str);
}
}
string TimeStr(int taim)
{
string sTaim;
int HH=TimeHour(taim); // Hour
int MM=TimeMinute(taim); // Minute
if (HH<10) sTaim = StringConcatenate(sTaim,"0",DoubleToStr(HH,0));
else sTaim = StringConcatenate(sTaim,DoubleToStr(HH,0));
if (MM<10) sTaim = StringConcatenate(sTaim,":0",DoubleToStr(MM,0));
else sTaim = StringConcatenate(sTaim,":",DoubleToStr(MM,0));
return(sTaim);
}
This is a great base to start with, going to do some extensive testing with this and will report back.
Mmm ... that's strange. Maybe because the margin is finished to open new orders.
However the 1.3.5 version has some bugs, so I suggest to use the 1.3.6 (inline) or better wait the 1.3.7 which will be published soon on another thread.
Thanks for the interest.
Just would like to remark that this work is completely free and I'm available to work together to improve the performances of the bot and give to people an instrument to gain money with Forex.
The scope is not to have a super profitable but also high risky bot, but instead a bot protecting the capital as much as possible, but also providing some interesting profits.
Regards,
A.
Funny that my trading method is so similar; My dd is low when using proper MM, (5% dd per every 10% profit).
Regards
Carlos
Thanks again for the constant updates :D
What are the hanovers for?
Thanks again for the constant updates :D
What are the hanovers for?
Utility functions I used to make some string elaborations ... they have to be installed under experts/include folder.
Moreover the backtest works only with one pair at a time. The one in the picture has been executed against EURUSD (the period is not important, you can choose anyone) with RiskPerTrade 10% .... I suspect there are some issues with 4 digits accounts, I need more investigation.
Thanks again for the constant updates :D
What are the hanovers for?
Utility functions I used to make some string elaborations ... they have to be installed under experts/include folder.
Moreover the backtest works only with one pair at a time. The one in the picture has been executed against EURUSD (the period is not important, you can choose anyone) with RiskPerTrade 10% .... I suspect there are some issues with 4 digits accounts, I need more investigation.
Ah ok, strange, I've placed them in experts/include, but the EA keeps greyed out and on backtest I can't enter the properties.
But yes, I'm on a 4 digit account
Thanks again for the constant updates :D
What are the hanovers for?
Utility functions I used to make some string elaborations ... they have to be installed under experts/include folder.
Moreover the backtest works only with one pair at a time. The one in the picture has been executed against EURUSD (the period is not important, you can choose anyone) with RiskPerTrade 10% .... I suspect there are some issues with 4 digits accounts, I need more investigation.
Ah ok, strange, I've placed them in experts/include, but the EA keeps greyed out and on backtest I can't enter the properties.
But yes, I'm on a 4 digit account

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
[EA] Charles-1.3.3:
Author: afabiani