#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==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(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)ssb)&&(precolag[0].close>ssb)&&(direcao==Buy)) return(true); if ((preco[0].closessb)&&(preco[0].close>ssblag)&&(direcao==Buy)) return(true); if ((preco[0].closegap_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].openbar[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;imax;//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(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(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].closegatilho.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); } };