671 lines
51 KiB
MQL5
671 lines
51 KiB
MQL5
#define ELEFANT_MAGIC 10
|
|
#define SHADOW_MAGIC 20
|
|
#define BUY_HOLD_MAGIC 30
|
|
#define SELL_HOLD_MAGIC 40
|
|
#define TREND_MAGIC 100
|
|
#define RETURN_MAGIC 200
|
|
#define GAP_MAGIC 50
|
|
#define PYTHON_MAGIC 60
|
|
|
|
class Signal//classe base
|
|
{
|
|
public:
|
|
string psymbol;
|
|
int patr;
|
|
ENUM_TIMEFRAMES timeframe;
|
|
int BuyMagic;
|
|
int SellMagic;
|
|
double myvol;
|
|
|
|
Signal(void){Init();}
|
|
void Reset(void){Init();}
|
|
|
|
virtual void InitFname(string fname){return;}
|
|
virtual void Init(void){return;}
|
|
virtual void Initspecific(double ¶ms[]){return;}
|
|
virtual void Initfixed(string Psymbol,int Patr,ENUM_TIMEFRAMES Timeframe,int buymagic,int sellmagic,double thisvol)
|
|
{
|
|
psymbol=Psymbol;
|
|
patr=Patr;
|
|
timeframe=Timeframe;
|
|
BuyMagic=buymagic;
|
|
SellMagic=sellmagic;
|
|
myvol=thisvol;
|
|
}
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao){return(false);}
|
|
virtual double Sl(void){return(0);}
|
|
virtual double Tp(void){return(0);}
|
|
virtual double Vol(void)
|
|
{
|
|
if (PositionSelect(psymbol))
|
|
{
|
|
//Print("Rebalanço");
|
|
//return(MathAbs(PositionGetDouble(POSITION_VOLUME)-myvol));
|
|
return(0);
|
|
}
|
|
else return(myvol);
|
|
}
|
|
virtual string PrintString(void){return("");}
|
|
virtual bool ClosePosition(bool selected)
|
|
{
|
|
if ((!selected)&&(PositionSelect(psymbol))) return (true);
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class BuyHold : public Signal
|
|
{
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalanço
|
|
{
|
|
if ((PositionGetDouble(POSITION_VOLUME)<myvol)&&direcao==Buy) {MyPrint(psymbol," Rebalanço compra");return(true);}
|
|
if ((PositionGetDouble(POSITION_VOLUME)>myvol)&&direcao==Sell) {MyPrint(psymbol," Rebalanço venda");return(true);}
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
if (direcao==Buy) return(true);
|
|
if (direcao==Sell) return(false);
|
|
return(false);
|
|
}
|
|
}
|
|
virtual double Vol(void)
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalance
|
|
{
|
|
//Print("Rebalanço");
|
|
return(MathAbs(PositionGetDouble(POSITION_VOLUME)-myvol));
|
|
}
|
|
else return(myvol);
|
|
}
|
|
};
|
|
|
|
class SellHold : public BuyHold
|
|
{
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalance
|
|
{
|
|
if ((PositionGetDouble(POSITION_VOLUME)>myvol)&&direcao==Buy) {MyPrint(psymbol," Rebalanço compra");return(true);}
|
|
if ((PositionGetDouble(POSITION_VOLUME)<myvol)&&direcao==Sell) {MyPrint(psymbol," Rebalanço venda");return(true);}
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
if (direcao==Buy) return(false);
|
|
if (direcao==Sell) return(true);
|
|
return(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
class BuyHoldSellNeutral : public Signal
|
|
{
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
if (psymbol!=NeutralAsset2)
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalanço
|
|
{
|
|
if ((PositionGetDouble(POSITION_VOLUME)<myvol)&&direcao==Buy) {MyPrint(psymbol," Rebalanço compra");return(true);}
|
|
if ((PositionGetDouble(POSITION_VOLUME)>myvol)&&direcao==Sell) {MyPrint(psymbol," Rebalanço venda");return(true);}
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
if (direcao==Buy) return(true);
|
|
if (direcao==Sell) return(false);
|
|
return(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalance
|
|
{
|
|
if ((PositionGetDouble(POSITION_VOLUME)>myvol)&&direcao==Buy) {MyPrint(psymbol," Rebalanço compra");return(true);}
|
|
if ((PositionGetDouble(POSITION_VOLUME)<myvol)&&direcao==Sell) {MyPrint(psymbol," Rebalanço venda");return(true);}
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
if (direcao==Buy) return(false);
|
|
if (direcao==Sell) return(true);
|
|
return(false);
|
|
}
|
|
}
|
|
}
|
|
virtual double Vol(void)
|
|
{
|
|
if (PositionSelect(psymbol))//Rebalance
|
|
{
|
|
//Print("Rebalanço");
|
|
return(MathAbs(PositionGetDouble(POSITION_VOLUME)-myvol));
|
|
}
|
|
else return(myvol);
|
|
}
|
|
};
|
|
|
|
class Shadow : public Signal
|
|
{
|
|
public:
|
|
bool AtrVar;//=false;//Usar janela variável com ATR
|
|
bool SignalOrig;//=true;//Sinal original - lag preço/código - lag ssb
|
|
virtual void Initspecific(double ¶ms[])
|
|
{
|
|
if (ArraySize(params)==2)
|
|
{
|
|
AtrVar=(bool)params[0];
|
|
SignalOrig=(bool)params[1];
|
|
}
|
|
}
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
double ssb=SSB(psymbol,timeframe,0);
|
|
double ssblag=SSB(psymbol,timeframe,25);
|
|
MqlRates preco[],precolag[];
|
|
CopyRates(psymbol,timeframe,0,1,preco);//na simulaçao diario é zero, deve ser mudado na simulação m1
|
|
CopyRates(psymbol,timeframe,25,1,precolag);
|
|
if (SignalOrig)
|
|
{
|
|
if ((preco[0].close>ssb)&&(precolag[0].close>ssb)&&(direcao==Buy)) return(true);
|
|
if ((preco[0].close<ssb)&&(precolag[0].close<ssb)&&(direcao==Sell)) return(true);
|
|
}
|
|
else
|
|
{
|
|
if ((preco[0].close>ssb)&&(preco[0].close>ssblag)&&(direcao==Buy)) return(true);
|
|
if ((preco[0].close<ssb)&&(preco[0].close<ssblag)&&(direcao==Sell)) return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class Gap : public Signal
|
|
{
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
MqlRates bar[];
|
|
ArraySetAsSeries(bar, true);
|
|
double ret[];
|
|
ArraySetAsSeries(ret, true);
|
|
//Usa 3 parâmetros da classe Signal
|
|
//usa o parâmetro patr (período do atr no menu da estratégia) para determinar qual o tamanho da janela de cálculo do desvio padrão
|
|
//usar o parâmetro timeframe (timeframe do atr no menu da estratégia) para determinar qual o timeframe do cálculo do desvio padrão e do gap
|
|
//usa o parâmetro psymbol para fazer o cálculo para o ativo da estratégia, tornando-a multiativo
|
|
CopyRates(psymbol, timeframe, 0, patr+1,bar);
|
|
ArrayResize(ret,ArraySize(bar)-1);
|
|
//for (int i=0;i<ArraySize(ret);i++) ret[i] = MathLog(bar[i+1].close/bar[i].close);
|
|
for (int i=0;i<ArraySize(ret);i++) ret[i] = bar[i+1].close/bar[i].close-1;
|
|
|
|
double gap_buy = (bar[0].open-bar[1].low)/bar[1].low;//-1;//abertura de hoje<mínimo de ontem=>gap_buy é negativo
|
|
double gap_sell = (bar[0].open-bar[1].high)/bar[1].high;//-1;//abertura de hoje>maximo de ontem=>gap_sell é positivo
|
|
|
|
double vol= MathStandardDeviation(ret);
|
|
//Estrutura de sinais da estrategia
|
|
bool signal_a_buy = gap_buy<-vol;
|
|
bool signal_a_sell = gap_sell>vol;
|
|
bool signal_b_buy = bar[0].open<bar[1].low;
|
|
bool signal_b_sell = bar[0].open>bar[1].high;
|
|
|
|
if ((signal_a_buy&&signal_b_buy)&&(direcao==Buy)) return(true);
|
|
if ((signal_a_sell&&signal_a_sell)&&(direcao==Sell)) return(true);
|
|
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class ProjecaoMaxMin : public Signal
|
|
{//equivale a retorno a preço
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
MqlRates preco[];
|
|
CopyRates(psymbol,timeframe,0,1,preco);
|
|
double volatilidade=Atr(psymbol,patr,timeframe,0);//estimativa da volatilidade, pode ser o atr por ex.
|
|
double alphamax=0.5,alphamin=0.5;
|
|
/*
|
|
//alphamax e alphamin determinados minimizando o desvio quadrático médio
|
|
alphamax=0.5;
|
|
alphamin=0.5;
|
|
double erromax=0;erromin=0;
|
|
for (int i=0;i<patr;i++)
|
|
{
|
|
erromax+=(preco[i].high-(preco[i].open+alphamax*volatilidade))*(preco[i].high-(preco[i].open+alphamax*volatilidade));
|
|
erromin+=(preco[i].low-(preco[i].open-alphamin*volatilidade))*(preco[i].low-(preco[i].open-alphamin*volatilidade));
|
|
}
|
|
double alphastep=0.1
|
|
bla bla bla
|
|
pensando bem, não acho que vai ser muito melhor que a estimativa abaixo, a não ser em tendências muito bem definidas
|
|
*/
|
|
double max= preco[0].open + alphamax*volatilidade;
|
|
double min= preco[0].open - alphamin*volatilidade;
|
|
double price=preco[0].close;//último preço (ou bid ou ask)
|
|
bool signal_buy = price<min;//compra se preço menor que a projeção do mínimo
|
|
bool signal_sell = price>max;//vende se preço maior que a projeção do máximo
|
|
|
|
if (signal_buy&&(direcao==Buy)) return(true);
|
|
if (signal_sell&&(direcao==Sell)) return(true);
|
|
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class PythonScripts: public Signal
|
|
{
|
|
public:
|
|
string script_name;
|
|
bool useticker,usevolume;
|
|
virtual void InitFname(string fname){script_name=fname;}
|
|
virtual void Initspecific(double ¶ms[])
|
|
{
|
|
if (ArraySize(params)==2)
|
|
{
|
|
useticker=(bool)params[0];
|
|
usevolume=(bool)params[1];
|
|
}
|
|
}
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
string outputfile=script_name+".out";
|
|
if (FileIsExist(outputfile)) FileDelete(outputfile);//Se o arquivo de saída existir, delete-o
|
|
|
|
RunPython(script_name);//Roda o script python
|
|
|
|
while (!FileIsExist(outputfile)) Sleep(1000);//espera o aquivo ser criado
|
|
|
|
int fhandle=FileOpen(outputfile,FILE_READ|FILE_CSV|FILE_TXT,";"); //Abre o arquivo para leitura
|
|
if (fhandle!=INVALID_HANDLE)
|
|
{
|
|
string fsymbol=FileReadString(fhandle);//Lê o ticker
|
|
ENUM_OP_TYPES fdirecao=None;
|
|
int dir=(int)FileReadNumber(fhandle);//Lê a direção
|
|
if (dir==1) fdirecao=Buy;//Converte a direção (não precisava kkkkk)
|
|
if (dir==-1) fdirecao=Sell;
|
|
double fvolume=FileReadNumber(fhandle);//Lê o volume
|
|
if (useticker?(fsymbol==psymbol):true)//Testa se o ativo no arquivo é o mesmo do objeto
|
|
{
|
|
if (usevolume) myvol=fvolume;//seta o novo volume
|
|
//testa a direção do sinal
|
|
if ((fdirecao==Buy)&&(direcao==Buy)) return(true);
|
|
if ((fdirecao==Sell)&&(direcao==Sell)) return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
enum REF_TYPES
|
|
{
|
|
Ref_price_maxmin,//Rompimento/Retorno Max,Min(Preço)
|
|
Ref_mean,//Cruzamento/Retorno Média
|
|
Ref_ssb,//Cruzamento/Retorno Ssb
|
|
Ref_price_minmax//Rompimento/Retorno Min,Max(Preço)
|
|
};
|
|
|
|
enum REF_PRICES_TYPES
|
|
{
|
|
Ref_pt_maxmin,//Max,Min
|
|
Ref_pt_max,//máximo
|
|
Ref_pt_min,//mínimo
|
|
Ref_pt_open,//abertura
|
|
Ref_pt_close,//fechamento
|
|
Ref_pt_median,//(max+min)/2
|
|
Ref_pt_typical,//(max+min+close)/3
|
|
Ref_pt_weighted//(max+min+open+close)/4
|
|
};
|
|
|
|
double Calc_refs(string psymbol,int period,ENUM_TIMEFRAMES timeframe,REF_TYPES type,REF_PRICES_TYPES price_type,double &max,double &min,int shift=0)
|
|
{
|
|
MqlRates rt[];
|
|
if (CopyRates(psymbol,timeframe,shift,period,rt)==period)
|
|
{
|
|
double ret=0;
|
|
double price=0;
|
|
max=-DBL_MAX;
|
|
min=DBL_MAX;
|
|
if ((type==Ref_mean)&&(price_type==Ref_pt_maxmin))
|
|
{
|
|
max=0;
|
|
min=0;
|
|
}
|
|
for (int i=0;i<period;i++)
|
|
{
|
|
switch(price_type)
|
|
{
|
|
case Ref_pt_maxmin:price=(rt[i].high+rt[i].low)/2.0;break;
|
|
case Ref_pt_max:price=rt[i].high;break;
|
|
case Ref_pt_min:price=rt[i].low;break;
|
|
case Ref_pt_open:price=rt[i].open;break;
|
|
case Ref_pt_close:price=rt[i].close;break;
|
|
case Ref_pt_median:price=(rt[i].high+rt[i].low)/2.0;break;
|
|
case Ref_pt_typical:price=(rt[i].high+rt[i].low+rt[i].close)/3.0;break;
|
|
case Ref_pt_weighted:price=(rt[i].high+rt[i].low+rt[i].open+rt[i].close)/4.0;break;
|
|
}
|
|
if ((type==Ref_mean)&&(price_type==Ref_pt_maxmin))
|
|
{
|
|
max+=rt[i].high;
|
|
min+=rt[i].low;
|
|
}
|
|
else
|
|
{
|
|
(price_type!=Ref_pt_maxmin)?max=MathMax(max,price):max=MathMax(max,rt[i].high);
|
|
(price_type!=Ref_pt_maxmin)?min=MathMin(min,price):min=MathMin(min,rt[i].low);
|
|
}
|
|
ret+=price;
|
|
}
|
|
switch(type)
|
|
{
|
|
case Ref_price_maxmin:break;
|
|
case Ref_price_minmax:break;
|
|
case Ref_mean:
|
|
ret/=(double)period;
|
|
if (price_type==Ref_pt_maxmin)
|
|
{
|
|
max/=(double)period;
|
|
min/=(double)period;
|
|
}
|
|
break;
|
|
case Ref_ssb:ret=(max+min)/2.0;break;
|
|
}
|
|
return(ret);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
class Trend : public Signal
|
|
{
|
|
public:
|
|
REF_TYPES Type;//=Ref_price_maxmin;//Tipo de estratégia
|
|
REF_PRICES_TYPES Price;//=Ref_pt_maxmin;//Tipo de preço
|
|
int Periodo;//=7;//Número de barras no sinal
|
|
double AtrFrac;//=0.0;//Fração do Atr de deslocamento
|
|
bool ConfCandle;//=false;//Usar candle de confirmação do rompimento
|
|
ENUM_TIMEFRAMES RefTimeframe;//Timeframe da referência
|
|
|
|
virtual void Initspecific(double ¶ms[])
|
|
{
|
|
if (ArraySize(params)==6)
|
|
{
|
|
Type=(REF_TYPES)params[0];
|
|
Price=(REF_PRICES_TYPES)params[1];
|
|
Periodo=(int)params[2];
|
|
AtrFrac=(double)params[3];
|
|
ConfCandle=(bool)params[4];
|
|
RefTimeframe=(ENUM_TIMEFRAMES)params[5];
|
|
}
|
|
}
|
|
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
MqlRates rt[];//candle confirmacao
|
|
CopyRates(psymbol,timeframe,0,1,rt);
|
|
double last=rt[0].close;//SymbolInfoDouble(psymbol,SYMBOL_LAST);
|
|
double ask=SymbolInfoDouble(psymbol,SYMBOL_ASK);
|
|
double bid=SymbolInfoDouble(psymbol,SYMBOL_BID);
|
|
double max,min;
|
|
double atr=Atr(psymbol,patr,timeframe,0);
|
|
CopyRates(psymbol,timeframe,1,1,rt);//na simulaçao diario comeca no zero, deve ser mudado na simulação m1
|
|
double ret=Calc_refs(psymbol,Periodo,RefTimeframe,Type,Price,max,min,1);
|
|
//if (PositionSelect(psymbol)){max=PositionGetDouble(POSITION_PRICE_OPEN);min=max;ret=max;}//parcelamento com sinal
|
|
switch (Type)
|
|
{
|
|
case Ref_price_maxmin:
|
|
if ((last>(max+AtrFrac*atr))&&(ConfCandle?rt[0].close>(max+AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last<(min-AtrFrac*atr))&&(ConfCandle?rt[0].close<(min-AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
case Ref_price_minmax:
|
|
if ((last>(min+AtrFrac*atr))&&(ConfCandle?rt[0].close>(min+AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last<(max-AtrFrac*atr))&&(ConfCandle?rt[0].close<(max-AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
case Ref_mean:
|
|
if (Price==Ref_pt_maxmin)
|
|
{
|
|
if ((last>(max+AtrFrac*atr))&&(ConfCandle?rt[0].close>(max+AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last<(min-AtrFrac*atr))&&(ConfCandle?rt[0].close<(min-AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
}
|
|
else
|
|
{
|
|
if ((last>(ret+AtrFrac*atr))&&(ConfCandle?rt[0].close>(ret+AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last<(ret-AtrFrac*atr))&&(ConfCandle?rt[0].close<(ret-AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
}
|
|
break;
|
|
case Ref_ssb:
|
|
if ((last>(ret+AtrFrac*atr))&&(ConfCandle?rt[0].close>(ret+AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last<(ret-AtrFrac*atr))&&(ConfCandle?rt[0].close<(ret-AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
}
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class Return : public Trend
|
|
{
|
|
public:
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
MqlRates rt[];//candle confirmacao
|
|
CopyRates(psymbol,timeframe,0,1,rt);//na simulaçao diario comeca no zero, deve ser mudado na simulação m1
|
|
double last=rt[0].close;//SymbolInfoDouble(psymbol,SYMBOL_LAST);
|
|
double ask=SymbolInfoDouble(psymbol,SYMBOL_ASK);
|
|
double bid=SymbolInfoDouble(psymbol,SYMBOL_BID);
|
|
double max,min;
|
|
double atr=Atr(psymbol,patr,timeframe,0);
|
|
CopyRates(psymbol,timeframe,1,1,rt);//na simulaçao diario comeca no zero, deve ser mudado na simulação m1
|
|
double ret=Calc_refs(psymbol,Periodo,RefTimeframe,Type,Price,max,min,1);
|
|
//if (PositionSelect(psymbol)){max=PositionGetDouble(POSITION_PRICE_OPEN);min=max;ret=max;}//parcelamento com sinal
|
|
switch (Type)
|
|
{
|
|
case Ref_price_maxmin:
|
|
if ((last<(max-AtrFrac*atr))&&(ConfCandle?rt[0].close<(max-AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last>(min+AtrFrac*atr))&&(ConfCandle?rt[0].close>(min+AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
case Ref_price_minmax:
|
|
//CopyRates(psymbol,timeframe,0,1,rt);
|
|
if ((last<(min-AtrFrac*atr))&&(ConfCandle?rt[0].close<(min-AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last>(max+AtrFrac*atr))&&(ConfCandle?rt[0].close>(max+AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
case Ref_mean:
|
|
if (Price==Ref_pt_maxmin)
|
|
{
|
|
if ((last<(max-AtrFrac*atr))&&(ConfCandle?rt[0].close<(max-AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last>(min+AtrFrac*atr))&&(ConfCandle?rt[0].close>(min+AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
}
|
|
else
|
|
{
|
|
if ((last<(ret-AtrFrac*atr))&&(ConfCandle?rt[0].close<(ret-AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last>(ret+AtrFrac*atr))&&(ConfCandle?rt[0].close>(ret+AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
}
|
|
break;
|
|
case Ref_ssb:
|
|
if ((last<(ret-AtrFrac*atr))&&(ConfCandle?rt[0].close<(ret-AtrFrac*atr):true)&&(direcao==Buy)) return(true);
|
|
if ((last>(ret+AtrFrac*atr))&&(ConfCandle?rt[0].close>(ret+AtrFrac*atr):true)&&(direcao==Sell)) return(true);
|
|
break;
|
|
}
|
|
return(false);
|
|
}
|
|
};
|
|
|
|
class CandlesElefant
|
|
{
|
|
public:
|
|
bool enable;
|
|
datetime data;
|
|
double min,max,tamanho;
|
|
CandlesElefant(void){enable=false;data=0;min=0;max=0;tamanho=0;}
|
|
void Init(void){enable=false;data=0;min=0;max=0;tamanho=0;}
|
|
void Reset(void){Init();}
|
|
};
|
|
|
|
class Elefante : public Signal
|
|
{
|
|
public:
|
|
CandlesElefant elefante,gatilho;
|
|
ENUM_OP_TYPES mydir;
|
|
bool RRFilter;//=true;//Usar filtro de Retorno/Risco
|
|
double RRFrac;//=0.33;//Fração RR
|
|
bool SSBFilter;//=true;//Usar filtro SSB
|
|
bool ConfCandle;//=true;//Usar candle de confirmação do rompimento
|
|
bool SlOrig;//=false;//SL original - extensão acima(abaixo) pivô/ponto médio do elefante
|
|
bool TpOrig;//=false;//TP original - extensão baixo(acima) pivô/extensão acima(abaixo) elefante
|
|
bool PivotCandle;//=false;//Usar candle de pivot - rompimento do pivô/elefante
|
|
bool BodyElefant;//=true;//Usar só o corpo do candle elefante
|
|
bool BodyPivot;//=false;//Usar só o corpo do candle pivô
|
|
|
|
virtual void Initspecific(double ¶ms[])
|
|
{
|
|
if (ArraySize(params)==10)
|
|
{
|
|
RRFilter=(bool)params[0];
|
|
RRFrac=(double)params[1];
|
|
SSBFilter=(bool)params[2];
|
|
ConfCandle=(bool)params[3];
|
|
SlOrig=(bool)params[4];
|
|
TpOrig=(bool)params[5];
|
|
PivotCandle=(bool)params[6];
|
|
BodyElefant=(bool)params[7];
|
|
BodyPivot=(bool)params[8];
|
|
mydir=(ENUM_OP_TYPES)params[9];
|
|
}
|
|
}
|
|
|
|
virtual void Init(void)
|
|
{
|
|
elefante.Init();
|
|
gatilho.Init();
|
|
mydir=None;
|
|
}
|
|
virtual bool SignalCheck(ENUM_OP_TYPES direcao)
|
|
{
|
|
MqlRates rt[];
|
|
ArraySetAsSeries(rt,true);
|
|
CopyRates(psymbol,timeframe,0,1,rt);
|
|
double preco=rt[0].close;//SymbolInfoDouble(psymbol,SYMBOL_LAST);
|
|
CopyRates(psymbol,timeframe,1,1,rt);
|
|
double ask=SymbolInfoDouble(psymbol,SYMBOL_ASK);
|
|
double bid=SymbolInfoDouble(psymbol,SYMBOL_BID);
|
|
double ssb=(SSBFilter?SSB(psymbol,timeframe,26):preco);
|
|
if ((MathAbs(rt[0].close-rt[0].open)>Atr(psymbol,patr,timeframe))&&(!elefante.enable))//verifica candle elefante
|
|
{
|
|
Reset();
|
|
if ((rt[0].close>rt[0].open)&&(preco>=ssb))
|
|
{
|
|
elefante.enable=true;
|
|
mydir=Buy;
|
|
}
|
|
else if((rt[0].close<rt[0].open)&&(preco<=ssb))
|
|
{
|
|
elefante.enable=true;
|
|
mydir=Sell;
|
|
}
|
|
elefante.data=rt[0].time;
|
|
elefante.tamanho=MathAbs(rt[0].close-rt[0].open);
|
|
elefante.min=(BodyElefant?MathMin(rt[0].open,rt[0].close):rt[0].low);
|
|
elefante.max=(BodyElefant?MathMax(rt[0].open,rt[0].close):rt[0].high);
|
|
}
|
|
|
|
if ((elefante.enable)&&(rt[0].time!=elefante.data))//verifica gatilho
|
|
{
|
|
if(PivotCandle)
|
|
{
|
|
if ((MathAbs(rt[0].close-rt[0].open)<(0.5*elefante.tamanho))&&(!gatilho.enable)//verifica tamanho
|
|
&&( ((rt[0].low>(0.5*elefante.min+0.5*elefante.max))&&(mydir==Buy)&&(preco>=ssb))
|
|
||((rt[0].high<(0.5*elefante.min+0.5*elefante.max))&&(mydir==Sell)&&(preco<=ssb)) )//verifica range
|
|
)
|
|
{
|
|
gatilho.enable=true;
|
|
gatilho.data=rt[0].time;
|
|
gatilho.tamanho=MathAbs(rt[0].close-rt[0].open);
|
|
gatilho.min=(BodyPivot?MathMin(rt[0].open,rt[0].close):rt[0].low);
|
|
gatilho.max=(BodyPivot?MathMax(rt[0].open,rt[0].close):rt[0].high);
|
|
}
|
|
else if (!gatilho.enable) Reset();//se não teve range ou tamanho, reseta
|
|
}
|
|
else
|
|
{
|
|
gatilho.enable=true;
|
|
gatilho.data=rt[0].time;
|
|
gatilho.tamanho=MathAbs(rt[0].close-rt[0].open);
|
|
gatilho.min=(BodyPivot?MathMin(rt[0].open,rt[0].close):rt[0].low);
|
|
gatilho.max=(BodyPivot?MathMax(rt[0].open,rt[0].close):rt[0].high);
|
|
}
|
|
|
|
if ( ((rt[0].low<(0.5*elefante.min+0.5*elefante.max))&&(mydir==Buy))//tendo gatilho ou nao se ficou fora do range deve desarmar
|
|
||((rt[0].high>(0.5*elefante.min+0.5*elefante.max))&&(mydir==Sell)) )//verifica range
|
|
Reset();
|
|
|
|
if ((!gatilho.enable)&&PivotCandle) Reset();//se entrou aqui e não setou gatilho, reseta
|
|
}
|
|
|
|
if ((elefante.enable)&&(gatilho.enable))//verifica disparo
|
|
{
|
|
if ( ((ask>=Entry())&&(mydir==Buy)&&(preco>=ssb)&&(ConfCandle?(rt[0].close>=Entry()):true)&&(direcao==Buy) )||
|
|
((bid<=Entry())&&(mydir==Sell)&&(preco<=ssb)&&(ConfCandle?(rt[0].close<=Entry()):true)&&(direcao==Sell) ) )//verifica rompimento gatilho
|
|
{
|
|
if (RRFilter)
|
|
{
|
|
double profit=MathAbs(Tp()-preco);
|
|
double loss=MathAbs(preco-Sl());
|
|
if (profit<(RRFrac*loss)) return(false);
|
|
return(true);
|
|
}
|
|
else return(true);
|
|
}
|
|
|
|
if ( (((rt[0].close<gatilho.min)&&(mydir==Buy))||((rt[0].close>gatilho.max)&&(mydir==Sell)))&&(rt[0].time!=gatilho.data) )
|
|
Reset();//desarma
|
|
}
|
|
return(false);
|
|
}
|
|
double Entry(void)
|
|
{
|
|
if(!PivotCandle)
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,elefante.max+1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,elefante.min-1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
}
|
|
else
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,gatilho.max+1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,gatilho.min-1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
}
|
|
return(0);
|
|
}
|
|
virtual double Sl(void)
|
|
{
|
|
if (SlOrig)
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,gatilho.min-1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,gatilho.max+1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
}
|
|
else
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,(0.5*elefante.min+0.5*elefante.max-1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE)),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,(0.5*elefante.min+0.5*elefante.max+1.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE)),true));
|
|
}
|
|
return(0);
|
|
}
|
|
virtual double Tp(void)
|
|
{
|
|
if (TpOrig)
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,gatilho.max+elefante.tamanho+2.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,gatilho.min-elefante.tamanho-2.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
}
|
|
else
|
|
{
|
|
if(mydir==Buy) return(NormalizePrice(psymbol,elefante.max+elefante.tamanho+2.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
if(mydir==Sell) return(NormalizePrice(psymbol,elefante.min-elefante.tamanho-2.0*SymbolInfoDouble(psymbol,SYMBOL_TRADE_TICK_SIZE),true));
|
|
}
|
|
return(0);
|
|
}
|
|
virtual string PrintString(void)
|
|
{
|
|
string ret=IntegerToString(elefante.enable)+" "+IntegerToString(gatilho.enable)+" "+IntegerToString(mydir);
|
|
return(ret);
|
|
}
|
|
};
|
|
|