//+------------------------------------------------------------------+ //| OptionSniffer.mq5 | //| Arthur Albano | //| https://www.mql5.com/en/users/arthuralbano/ | //+------------------------------------------------------------------+ #include #define SWAP(A, B) { A += B; B = A - B; A -= B; } #define SORT(a,b,c) {if(a > b) SWAP(a,b) if(a > c) SWAP(a,c) if (b>c) SWAP(b,c) } //+------------------------------------------------------------------+ //| Estruturas | //+------------------------------------------------------------------+ enum CalcMode { VWAP,//Session Average Weighted Last,//Last deal quote AskBidWatch,//Watch(Ask+Bid)/2 Median//Mediana }; enum showSerie { Current,//Current Next,//Next Next_2x//Next Next }; struct sOption { string strSymbol; ENUM_SYMBOL_OPTION_RIGHT enRight; double dbK; double dbP; double dbC; ulong dtExpiration; ulong dtLastDeal; }; struct stcDeal { long lPositionID; string strSymbol; ENUM_DEAL_TYPE enType; ulong dtTime; double dbVolume; double dbPrice; long lTicket; /*------------------------------ long lOrder; long lTime_msc; ENUM_DEAL_ENTRY enEntry; long lMagic; ENUM_DEAL_REASON enReason; double dbComission; double dbSwap; double dbProfit; double dbFee; double dbSL; double dbTP; string strComment; ---------------------------------*/ //double dbK; }; //+------------------------------------------------------------------+ //| Entradas | //+------------------------------------------------------------------+ sinput group "Globais"; sinput CalcMode inpCalcMode=Median;// Modo de Cálculo: sinput datetime inpMaxExpiration=D'2023.12.31 23:00:00';//Máxima expiração: sinput int inpSecondPlane=5;//Atualizações em segundo plano (s): sinput group "Ativo"; sinput string inpNextCall="";//Rolar Call para: sinput string inpNextPut="";//Rolar Put para: sinput string inpBlackList="";//Opções para ignorar: sinput group "Options"; sinput showSerie inpShowSerie=Next;//Série: sinput bool inpShowNegativeDeltaX=true;//Mostrar com diferença de prêmios negativo: sinput bool inpBreakMinorK=true;//Mostrar com ponto de equilibrio menor que atual: sinput bool inpPlotGraph=false;//Modo Gráfico ? sinput double inpFaixaK=100.0;//Faixa de Strikes (%): sinput group "Option Price Model"; sinput datetime inpExpirationDI=D'2024.01.24 23:59';//Expiração DI: sinput double inpr_0=13.625;//Índice DI: //sinput datetime inpNextExpiration=D'2023.11.18 23:59';//Próximo Exercício: //+------------------------------------------------------------------+ //| Globais | //+------------------------------------------------------------------+ const double cCoust=2.49; string strStatus=""; string strComment=""; string strFile=""; sOption arrBruteOptions[];//Usado como basse para carregar o arrOptions ( localmente em EA() ) já ordenado bool bImprimiu=false; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { LoadBruteOptions(); EA(); EventSetTimer(1); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectsDeleteAll(0,"OptionSniffer"); EventKillTimer(); Comment(""); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { EA(); } //+------------------------------------------------------------------+ //| Função Principal | //+------------------------------------------------------------------+ void EA() { if((MathMod((double)TimeLocal(),inpSecondPlane)==0.0))LoadBruteOptions(); ulong vSort[][2]; ZeroMemory(vSort); ArrayResize(vSort,ArraySize(arrBruteOptions)); for(int i=0;i=0;i--) { ulHistoryDealTicket=HistoryDealGetTicket(i); if( (SymbolInfoInteger(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_RIGHT)==SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)) &&(OptionBasis(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL))==OptionBasis(_Symbol)) ) { if( (SymbolInfoInteger(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL) &&(HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE)==DEAL_TYPE_SELL) ) { dbB=//SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE);//+HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE); dbB=((SymbolInfoInteger(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?1:-1)*HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE))+SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE); break; } } } } sOption stcBest_E; ZeroMemory(stcBest_E); double dbE_Best=-99999.99; sOption stcBest_B; ZeroMemory(stcBest_B); double dbB_Best=(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?-9999.99:99999.99); // sOption stcRollP; ZeroMemory(stcRollP); // sOption stcRollC; ZeroMemory(stcRollC); dbS=SymbolPrice(OptionBasis(_Symbol),inpCalcMode); lDaysToExpirate=(SymbolInfoInteger(_Symbol,SYMBOL_EXPIRATION_TIME)-TimeLocal())/86400; strComment=StringFormat("%s, " ,OptionBasis(_Symbol)); strComment+=IntegerToString(lDaysToExpirate)+" days to "+nextOptionSerie(StringSubstr(_Symbol,4,1))+" series."; strComment+="\n"; strComment+=StringFormat("S=%.2f, "+(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?"C=":"P=")+"%.2f, B=%.2f, OPM=%.4f\n",SymbolPrice(OptionBasis(_Symbol),inpCalcMode),SymbolPrice(_Symbol,inpCalcMode),dbB,OptionPrice(_Symbol)); strComment+="\n\n"; for(int i=0;i(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP)) ) { dbE=(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?MathMax(0,arrOptions[i].dbC-MathMax(0,SymbolPrice(OptionBasis(_Symbol),inpCalcMode)-arrOptions[i].dbK)):MathMax(0,arrOptions[i].dbP-MathMax(0,arrOptions[i].dbK-SymbolPrice(OptionBasis(_Symbol),inpCalcMode)))); //dbY=dbE/(2/(1/(dbS+dbE)+1/dbS)); dbY=(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP)/arrOptions[i].dbK; dbYperMonth=dbY/lDaysToExpirate*30; if((dbE>dbE_Best)&&((arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP)>=SymbolPrice(_Symbol,inpCalcMode))) { dbE_Best=dbE; stcBest_E.strSymbol=arrOptions[i].strSymbol; stcBest_E.enRight=arrOptions[i].enRight; stcBest_E.dbK=arrOptions[i].dbK; stcBest_E.dbC=arrOptions[i].dbC; stcBest_E.dbP=arrOptions[i].dbP; stcBest_E.dtExpiration=arrOptions[i].dtExpiration; stcBest_E.dtExpiration=arrOptions[i].dtLastDeal; if(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL) { if((arrOptions[i].dbK+arrOptions[i].dbC)>=dbB) { // stcRollC.strSymbol=arrOptions[i].strSymbol; // stcRollC.enRight=arrOptions[i].enRight; // stcRollC.dbK=arrOptions[i].dbK; // stcRollC.dbC=arrOptions[i].dbC; // stcRollC.dbP=arrOptions[i].dbP; // stcRollC.dtExpiration=arrOptions[i].dtExpiration; // stcRollC.dtExpiration=arrOptions[i].dtLastDeal; } } else { if((arrOptions[i].dbK-arrOptions[i].dbP)<=dbB) { // stcRollP.strSymbol=arrOptions[i].strSymbol; // stcRollP.enRight=arrOptions[i].enRight; // stcRollP.dbK=arrOptions[i].dbK; // stcRollP.dbC=arrOptions[i].dbC; // stcRollP.dbP=arrOptions[i].dbP; // stcRollP.dtExpiration=arrOptions[i].dtExpiration; // stcRollP.dtExpiration=arrOptions[i].dtLastDeal; } } if(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL) if(arrOptions[i].dbC>=SymbolPrice(_Symbol,inpCalcMode)) if(dbB_Best<(arrOptions[i].dbK+arrOptions[i].dbC)) { dbB_Best=(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC:arrOptions[i].dbK-arrOptions[i].dbP); stcBest_B.strSymbol=arrOptions[i].strSymbol; stcBest_B.enRight=arrOptions[i].enRight; stcBest_B.dbK=arrOptions[i].dbK; stcBest_B.dbC=arrOptions[i].dbC; stcBest_B.dbP=arrOptions[i].dbP; stcBest_B.dtExpiration=arrOptions[i].dtExpiration; stcBest_B.dtExpiration=arrOptions[i].dtLastDeal; } if(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_PUT) if(arrOptions[i].dbP>=SymbolPrice(_Symbol,inpCalcMode)) if(dbB_Best>(arrOptions[i].dbK-arrOptions[i].dbP)) { dbB_Best=(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC:arrOptions[i].dbK-arrOptions[i].dbP); stcBest_B.strSymbol=arrOptions[i].strSymbol; stcBest_B.enRight=arrOptions[i].enRight; stcBest_B.dbK=arrOptions[i].dbK; stcBest_B.dbC=arrOptions[i].dbC; stcBest_B.dbP=arrOptions[i].dbP; stcBest_B.dtExpiration=arrOptions[i].dtExpiration; stcBest_B.dtExpiration=arrOptions[i].dtLastDeal; } } } } // //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> OPÇÕES // if(SymbolInfoDouble(_Symbol,SYMBOL_OPTION_STRIKE)>0.0) { strComment+="Symbol; K; "+(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?"C":"P")+"; B; E; Y; y "+(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?"dC":"dP")+" OPM\n"; strComment+="------------------------------------------------------------------------------------------------------\n"; strFile="Symbol;S;K;C/P;B;E;Y;y;Mod\n"; if((stcBest_B.dbK>0.0)&&(stcBest_B.dbK<(dbS-(dbS*(inpFaixaK/100))))) { strComment+="\n"; strComment+=StringFormat("%s: %.2f; %.2f; %.2f; %.2f; %.2f%%; %.2f%%; %.2f; %.2f >B\n", stcBest_B.strSymbol, stcBest_B.dbK, (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbC:stcBest_B.dbP), (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbK+stcBest_B.dbC:stcBest_B.dbK-stcBest_B.dbP), dbB_Best, 100*dbY, 100*dbYperMonth, (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbC:stcBest_B.dbP)-SymbolPrice(_Symbol,inpCalcMode), OptionPrice(stcBest_B.strSymbol) ); } if((stcBest_E.dbK>0.0)&&(stcBest_E.dbK<(dbS-(dbS*(inpFaixaK/100))))) { strComment+=StringFormat("%s: %.2f; %.2f; %.2f; %.2f; %.2f%%; %.2f%%; %.2f; %.2f >E\n", stcBest_E.strSymbol, stcBest_E.dbK, (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbC:stcBest_E.dbP), (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbK+stcBest_E.dbC:stcBest_E.dbK-stcBest_E.dbP), dbE_Best, 100*dbY, 100*dbYperMonth, (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbC:stcBest_E.dbP)-SymbolPrice(_Symbol,inpCalcMode), OptionPrice(stcBest_E.strSymbol) ); } double K[]={}; double X[]={}; double X0[]={}; ZeroMemory(K);ZeroMemory(X);ZeroMemory(X0); for(int i=0;i=0.0)||inpShowNegativeDeltaX) &&((arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC>dbB:arrOptions[i].dbK-arrOptions[i].dbP(dbS-(dbS*(inpFaixaK/100)))) &&(arrOptions[i].dbK<(dbS+(dbS*(inpFaixaK/100)))) ) { ArrayResize(K,K.Size()+1);ArrayResize(X,X.Size()+1);ArrayResize(X0,X0.Size()+1); K[K.Size()-1]=arrOptions[i].dbK;X[X.Size()-1]=OptionPrice(arrOptions[i].strSymbol);X0[X.Size()-1]=(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP); strComment+=StringFormat("%s: %.2f; %.2f; %.2f; %.2f; %.2f%%; %.2f%%; %.2f; %.2f", arrOptions[i].strSymbol, arrOptions[i].dbK, (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP), (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC:arrOptions[i].dbK-arrOptions[i].dbP), dbE, 100*dbY, 100*dbYperMonth, (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP)-SymbolPrice(_Symbol,inpCalcMode), OptionPrice(arrOptions[i].strSymbol) ); if(arrOptions[i].strSymbol==stcBest_E.strSymbol)strComment+=" >E "; if(arrOptions[i].strSymbol==stcBest_B.strSymbol)strComment+=" >B "; strComment+="\n"; } strFile+=StringFormat("%s;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f\n", arrOptions[i].strSymbol, dbS, arrOptions[i].dbK, (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP), (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC:arrOptions[i].dbK-arrOptions[i].dbP), dbE, 100*dbY, 100*dbYperMonth, OptionPrice(arrOptions[i].strSymbol) ); } } if((stcBest_B.dbK>0.0)&&(stcBest_B.dbK>(dbS+(dbS*(inpFaixaK/100))))) { strComment+=StringFormat("%s: %.2f; %.2f; %.2f; %.2f; %.2f%%; %.2f%%; %.2f; %.2f >B\n", stcBest_B.strSymbol, stcBest_B.dbK, (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbC:stcBest_B.dbP), (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbK+stcBest_B.dbC:stcBest_B.dbK-stcBest_B.dbP), dbB_Best, 100*dbY, 100*dbYperMonth, (stcBest_B.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_B.dbC:stcBest_B.dbP)-SymbolPrice(_Symbol,inpCalcMode), OptionPrice(stcBest_B.strSymbol) ); } if((stcBest_E.dbK>0.0)&&(stcBest_E.dbK>(dbS+(dbS*(inpFaixaK/100))))) { strComment+=StringFormat("%s: %.2f; %.2f; %.2f; %.2f; %.2f%%; %.2f%%; %.2f; %.2f >E\n", stcBest_E.strSymbol, stcBest_E.dbK, (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbC:stcBest_E.dbP), (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbK+stcBest_E.dbC:stcBest_E.dbK-stcBest_E.dbP), dbE_Best, 100*dbY, 100*dbYperMonth, (stcBest_E.enRight==SYMBOL_OPTION_RIGHT_CALL?stcBest_E.dbC:stcBest_E.dbP)-SymbolPrice(_Symbol,inpCalcMode), OptionPrice(stcBest_E.strSymbol) ); } // strComment+="\nRoll to "+(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?stcRollC.strSymbol:stcRollP.strSymbol); if((inpPlotGraph)&&(SymbolInfoDouble(_Symbol,SYMBOL_OPTION_STRIKE)>0.0)) { ObjectDelete(0,"OptionSniffer_Graph"); ChartSetInteger(0,CHART_SHOW_DATE_SCALE,0); ChartSetInteger(0,CHART_SHOW_PRICE_SCALE,0); ChartSetInteger(0,CHART_SHIFT,0); CGraphic graphic; graphic.Create(0,"OptionSniffer_Graph",0,0,0,(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS),(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS)); graphic.BackgroundMain(OptionBasis(_Symbol)+" ("+DoubleToString(dbS,2)+")"+" @ "+TimeToString(TimeCurrent(),TIME_DATE)); graphic.BackgroundMainSize(12); graphic.XAxis().NameSize(12); graphic.XAxis().Name("Strike (K)"); graphic.XAxis().ValuesFormat("%.2f"); graphic.YAxis().NameSize(12); graphic.YAxis().Name("Premium ("+(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?"C":"P")+")"); graphic.YAxis().ValuesFormat("%.2f"); double Sx[2]={dbS,dbS}; double dbGraphXmax = MathMax(MathMax(X0[0],X[0]),MathMax(X0[ArraySize(X0)-1],X[ArraySize(X)-1])); double Sy[2]={0.0,dbGraphXmax}; CCurve *CCurveS = graphic.CurveAdd(Sx,Sy,ColorToARGB(clrChartreuse,255),CURVE_STEPS,OptionBasis(_Symbol)); CCurve *CCurveOPM = graphic.CurveAdd(K,X,0x000099,CURVE_LINES,"OPM"); CCurveOPM.LinesSmooth(true); CCurve *CCUrveX0 = graphic.CurveAdd(K,X0,0x009900,CURVE_POINTS,"Premium"); graphic.CurvePlotAll(); graphic.Update(); } else { ChartSetInteger(0,CHART_SHOW_DATE_SCALE,1); ChartSetInteger(0,CHART_SHOW_PRICE_SCALE,1); ChartSetInteger(0,CHART_SHIFT,1); } } else { // //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> ATIVO // int p=0; strComment=""; stcDeal arrDealsSim[]; ZeroMemory(arrDealsSim); ulHistoryDealTicket=0; HistorySelect(0,TimeCurrent()); for(int i=0;i0.0) ) { ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; arrDealsSim[p].lPositionID=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_POSITION_ID); arrDealsSim[p].strSymbol=HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL); arrDealsSim[p].dbVolume=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_VOLUME); arrDealsSim[p].dtTime=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TIME); if(SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE)>0.0) { arrDealsSim[p].enType=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?(ENUM_DEAL_TYPE)HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE):((ENUM_DEAL_TYPE)HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE)==DEAL_TYPE_SELL?(ENUM_DEAL_TYPE)DEAL_TYPE_BUY:(ENUM_DEAL_TYPE)DEAL_TYPE_SELL)); arrDealsSim[p].dbPrice=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE)+HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE):SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE)-HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE)); } else { arrDealsSim[p].enType=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE); arrDealsSim[p].dbPrice=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE); } arrDealsSim[p].lTicket=(long)ulHistoryDealTicket; } } ulPositionTicket=0; for(int i=0;i0) if(OptionBasis(PositionGetSymbol(i))==_Symbol) { ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; arrDealsSim[p].lPositionID=PositionGetInteger(POSITION_IDENTIFIER); arrDealsSim[p].strSymbol=PositionGetSymbol(i); arrDealsSim[p].dbVolume=PositionGetDouble(POSITION_VOLUME); //arrDealsSim[p].dtTime=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME)+TimeCurrent())/2; arrDealsSim[p].dtTime=TimeCurrent(); arrDealsSim[p].enType=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?DEAL_TYPE_BUY:DEAL_TYPE_SELL); arrDealsSim[p].dbPrice=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE)+SymbolPrice(arrDealsSim[p].strSymbol,inpCalcMode):SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE)-SymbolPrice(arrDealsSim[p].strSymbol,inpCalcMode)); arrDealsSim[p].lTicket=(long)ulPositionTicket; } } if(StringLen(inpNextCall)>0) //-------------------------------------------------------Roll Call para o Symbol informado explícitamente. (input) { if(SymbolInfoDouble(inpNextCall,SYMBOL_OPTION_STRIKE)>0.0) { if(SymbolInfoInteger(inpNextCall,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL) { ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; arrDealsSim[p].lPositionID=0; arrDealsSim[p].strSymbol=inpNextCall; arrDealsSim[p].dbVolume=0.0; arrDealsSim[p].dtTime=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME)+TimeCurrent())/2; arrDealsSim[p].enType=DEAL_TYPE_SELL; arrDealsSim[p].dbPrice=SymbolInfoDouble(inpNextCall,SYMBOL_OPTION_STRIKE)+SymbolPrice(inpNextCall,inpCalcMode); arrDealsSim[p].lTicket=0; } else { strComment+="Erro: "+inpNextCall+" não é uma opção de compra (CALL)!"; } } else { strComment+="Erro: "+inpNextCall+" não é Opção!\n\n"; } } else { //-------------------------------------------------------------------------------------------------------------------------------------------------Roll Call para a Ordem string strSymbolOrder=""; ulong ulOrderTicket=0; for(int i=0;i=0;i--) { if((SymbolInfoInteger(arrDealsSim[i].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL)&&(arrDealsSim[i].enType==DEAL_TYPE_SELL)) { iDealB=i; break; } } double dbCurrentExtrinsic=0.0; ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; for(int i=(ArraySize(arrOptions)-1);i>=0;i--) { if( nextOptionSerie(StringSubstr(arrDealsSim[iDealB].strSymbol,4,1))==StringSubstr(arrOptions[i].strSymbol,4,1) &&((arrOptions[i].dbK+arrOptions[i].dbC)>arrDealsSim[iDealB].dbPrice) &&(dbCurrentExtrinsic<((arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?MathMax(0,arrOptions[i].dbC-MathMax(0,SymbolPrice(OptionBasis(arrOptions[i].strSymbol),inpCalcMode)-arrOptions[i].dbK)):MathMax(0,arrOptions[i].dbP-MathMax(0,arrOptions[i].dbK-SymbolPrice(OptionBasis(arrOptions[i].strSymbol),inpCalcMode)))))) &&(arrOptions[i].dbC>=SymbolPrice(arrDealsSim[iDealB].strSymbol,inpCalcMode)) &&(StringFind(inpBlackList,arrOptions[i].strSymbol,0)<0) //&&(SymbolInfoInteger(arrOptions[i].strSymbol,SYMBOL_EXPIRATION_TIME)0) { if(SymbolInfoDouble(inpNextPut,SYMBOL_OPTION_STRIKE)>0.0) { if(SymbolInfoInteger(inpNextPut,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT) { ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; arrDealsSim[p].lPositionID=0; arrDealsSim[p].strSymbol=inpNextPut; arrDealsSim[p].dbVolume=0.0; arrDealsSim[p].dtTime=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME)+TimeCurrent())/2; arrDealsSim[p].enType=DEAL_TYPE_BUY; arrDealsSim[p].dbPrice=SymbolInfoDouble(inpNextPut,SYMBOL_OPTION_STRIKE)-SymbolPrice(inpNextPut,inpCalcMode); arrDealsSim[p].lTicket=0; strObjectName=StringFormat( "OptionSniffer #%.0f %s %.0f %s at %.4f", arrDealsSim[p].lTicket, StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrDealsSim[p].enType),10,4), arrDealsSim[p].dbVolume, arrDealsSim[p].strSymbol, arrDealsSim[p].dbPrice ); // ObjectCreate(0, // strObjectName+" EXPIRATION", // OBJ_ARROW_STOP, // 0, // SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME), // SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE) // );ObjectSetInteger(0,strObjectName+" EXPIRATION",OBJPROP_COLOR,clrBlue); // ObjectCreate(0, // strObjectName+" OPC", // OBJ_ARROW_UP, // 0, // arrDealsSim[p].dtTime, // SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE)-OptionPrice(arrDealsSim[p].strSymbol) // ); ObjectSetInteger(0,strObjectName+" Model",OBJPROP_COLOR,clrBlue); } else { strComment+="Erro: "+inpNextPut+" não é uma opção de venda (PUT)!"; } } else { strComment+="Erro: "+inpNextPut+" não é Opção!"; } } else //-------------------------------------------------------Roll Put para o Symbol calculado { int iDealB=0; for(int i=(ArraySize(arrDealsSim)-1);i>=0;i--) { if((SymbolInfoInteger(arrDealsSim[i].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT)&&(arrDealsSim[i].enType==DEAL_TYPE_BUY)) { iDealB=i; break; } } //PrintFormat("%s %.2f", arrDealsSim[iDealB].strSymbol, arrDealsSim[iDealB].dbPrice ); double dbCurrentExtrinsic=0.0; ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1); p=ArraySize(arrDealsSim);p--; for(int i=(ArraySize(arrOptions)-1);i>=0;i--) { if( nextOptionSerie(StringSubstr(arrDealsSim[iDealB].strSymbol,4,1))==StringSubstr(arrOptions[i].strSymbol,4,1) &&((arrOptions[i].dbK-arrOptions[i].dbP)=SymbolPrice(arrDealsSim[iDealB].strSymbol,inpCalcMode)) //&&(SymbolInfoInteger(arrOptions[i].strSymbol,SYMBOL_EXPIRATION_TIME)0) { ObjectCreate(0, strObjectName+" EXPIRATION", OBJ_ARROW_STOP, 0, SymbolInfoInteger(arrDealsSim[i].strSymbol,SYMBOL_EXPIRATION_TIME), SymbolInfoDouble(arrDealsSim[i].strSymbol,SYMBOL_OPTION_STRIKE) );ObjectSetInteger(0,strObjectName+" EXPIRATION",OBJPROP_COLOR,(SymbolInfoInteger(PositionGetString(POSITION_SYMBOL),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?clrBlue:clrRed)); } } } } int iDeal=1; stcDeal lastDealOption; ZeroMemory(lastDealOption); strComment+=" Quem Vende a CALL TEM o DEVER de VENDER a ação no vencimento pelo STRIKE.\n"; for(int i=0;i0.0) if(SymbolInfoInteger(arrDealsSim[i].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL) { strComment+=StringFormat("%3.0f. %s %4s %s %.4f", iDeal++, arrDealsSim[i].strSymbol, StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrDealsSim[i].enType),10,5), (arrDealsSim[i].dbVolume>0.0?TimeToString(arrDealsSim[i].dtTime,TIME_DATE|TIME_MINUTES|TIME_SECONDS):(arrDealsSim[i].dbVolume<0.0?" ORDER ":" SIMULATED ")), arrDealsSim[i].dbPrice ); if(i>0) { if(lastDealOption.dbPrice>0.0) { strObjectName=StringFormat( "OptionSniffer #%.0f %s %.0f %s at %.4f Trend", arrDealsSim[i].lTicket, StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrDealsSim[i].enType),10,4), arrDealsSim[i].dbVolume, arrDealsSim[i].strSymbol, arrDealsSim[i].dbPrice ); ObjectCreate( 0, strObjectName, OBJ_TREND, 0, arrDealsSim[i].dtTime, arrDealsSim[i].dbPrice, lastDealOption.dtTime, lastDealOption.dbPrice ); ObjectSetInteger(0,strObjectName,OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,strObjectName,OBJPROP_COLOR,clrDarkSlateGray); if(arrDealsSim[i].enType==DEAL_TYPE_BUY)strComment+=StringFormat(" %.4f %.2f%%", lastDealOption.dbPrice-arrDealsSim[i].dbPrice, 100*(lastDealOption.dbPrice-arrDealsSim[i].dbPrice)/(2/(1/lastDealOption.dbPrice+1/arrDealsSim[i].dbPrice)) ); if(arrDealsSim[i].enType==DEAL_TYPE_BUY) { ObjectCreate(0,strObjectName+" Yield",OBJ_TEXT,0,(arrDealsSim[i].dtTime+lastDealOption.dtTime)/2,(arrDealsSim[i].dbPrice+lastDealOption.dbPrice)/2); ObjectSetString(0,strObjectName+" Yield",OBJPROP_TEXT, StringFormat("%.2f%%",100*(lastDealOption.dbPrice-arrDealsSim[i].dbPrice)/(2/(1/lastDealOption.dbPrice+1/arrDealsSim[i].dbPrice)))); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_FONTSIZE,8); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_ANCHOR,ANCHOR_CENTER); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_COLOR,(lastDealOption.dbPrice>arrDealsSim[i].dbPrice?clrLime:clrRed)); } } } lastDealOption=arrDealsSim[i]; strComment+="\n"; } } iDeal=1; ZeroMemory(lastDealOption); strComment+="\n"; strComment+=" Quem Vende a PUT TEM o DEVER de COMPRAR a ação no vencimento pelo STRIKE.\n"; for(int i=0;i0.0) if(SymbolInfoInteger(arrDealsSim[i].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT) { strComment+=StringFormat("%3.0f. %s %4s %s %.4f", iDeal++, arrDealsSim[i].strSymbol, StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrDealsSim[i].enType),10,5), (arrDealsSim[i].dbVolume>0.0?TimeToString(arrDealsSim[i].dtTime,TIME_DATE|TIME_MINUTES|TIME_SECONDS):" SIMULATED "), arrDealsSim[i].dbPrice ); if(i>0) { if(lastDealOption.dbPrice>0.0) { strObjectName=StringFormat( "OptionSniffer #%.0f %s %.0f %s at %.4f Trend", arrDealsSim[i].lTicket, StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrDealsSim[i].enType),10,4), arrDealsSim[i].dbVolume, arrDealsSim[i].strSymbol, arrDealsSim[i].dbPrice ); ObjectCreate( 0, strObjectName, OBJ_TREND, 0, arrDealsSim[i].dtTime, arrDealsSim[i].dbPrice, lastDealOption.dtTime, lastDealOption.dbPrice ); if(arrDealsSim[i].enType==DEAL_TYPE_BUY)strComment+=StringFormat(" %.4f %.2f%%", lastDealOption.dbPrice-arrDealsSim[i].dbPrice, 100*(lastDealOption.dbPrice-arrDealsSim[i].dbPrice)/(2/(1/lastDealOption.dbPrice+1/arrDealsSim[i].dbPrice)) ); if((arrDealsSim[i].enType==DEAL_TYPE_BUY)&&(iDeal>3)) { ObjectCreate(0,strObjectName+" Yield",OBJ_TEXT,0,(arrDealsSim[i].dtTime+lastDealOption.dtTime)/2,(arrDealsSim[i].dbPrice+lastDealOption.dbPrice)/2); ObjectSetString(0,strObjectName+" Yield",OBJPROP_TEXT, StringFormat("%.2f%%",100*(lastDealOption.dbPrice-arrDealsSim[i].dbPrice)/(2/(1/lastDealOption.dbPrice+1/arrDealsSim[i].dbPrice)))); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_FONTSIZE,8); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_ANCHOR,ANCHOR_CENTER); ObjectSetInteger(0,strObjectName+" Yield",OBJPROP_COLOR,(lastDealOption.dbPrice>arrDealsSim[i].dbPrice?clrLime:clrRed)); } ObjectSetInteger(0,strObjectName,OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,strObjectName,OBJPROP_COLOR,clrDarkSlateGray); } } lastDealOption=arrDealsSim[i]; strComment+="\n"; } } ObjectCreate(0,"OptionSniffer_SymbolPrice",OBJ_HLINE,0,0,SymbolPrice(_Symbol,inpCalcMode));ObjectSetInteger(0,"OptionSniffer_SymbolPrice",OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,"OptionSniffer_SymbolPrice",OBJPROP_COLOR,clrYellow); dbS=SymbolPrice(_Symbol,inpCalcMode); strFile="Symbol;S;K;C/P;B;E;Y;y;Mod\n"; for(int i=0;i0.0) &&((SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL)||(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT)) &&((StringSubstr(SymbolInfoString(SymbolName(i,false),SYMBOL_ISIN),2,5)==ISINtoSymbol(SymbolInfoString(_Symbol,SYMBOL_ISIN)))||((StringSubstr(SymbolInfoString(SymbolName(i,false),SYMBOL_ISIN),2,5)==StringSubstr(SymbolInfoString(_Symbol,SYMBOL_ISIN),2,5)))) &&(SymbolInfoInteger(SymbolName(i,false),SYMBOL_EXPIRATION_TIME)TimeLocal()) ) { SymbolSelect(SymbolName(i,false),true); ArrayResize(arrBruteOptions,ArraySize(arrBruteOptions)+1); arrBruteOptions[ArraySize(arrBruteOptions)-1].strSymbol=SymbolName(i,false); arrBruteOptions[ArraySize(arrBruteOptions)-1].enRight=(ENUM_SYMBOL_OPTION_RIGHT)SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT); arrBruteOptions[ArraySize(arrBruteOptions)-1].dtExpiration=SymbolInfoInteger(SymbolName(i,false),SYMBOL_EXPIRATION_TIME); arrBruteOptions[ArraySize(arrBruteOptions)-1].dbK=SymbolInfoDouble(SymbolName(i,false),SYMBOL_OPTION_STRIKE); if(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL) arrBruteOptions[ArraySize(arrBruteOptions)-1].dbC=SymbolPrice(SymbolName(i,false),inpCalcMode); if(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT) arrBruteOptions[ArraySize(arrBruteOptions)-1].dbP=SymbolPrice(SymbolName(i,false),inpCalcMode); arrBruteOptions[ArraySize(arrBruteOptions)-1].dtLastDeal=SymbolInfoInteger(SymbolName(i,false),SYMBOL_TIME); } } strStatus=""; Comment(strStatus+"\n"+strComment); } //+------------------------------------------------------------------+ //| Próxima séria da Opção | //+------------------------------------------------------------------+ string nextOptionSerie(const string strSymbol) { string strReturn=""; string strCall="ABCDEFGHIJKL"; string strPut="MNOPQRSTUVWX"; string strSerieSymbol=strSymbol; if(StringFind(strCall,strSerieSymbol,0)>=0) strReturn=StringSubstr(strCall,StringFind(strCall,strSerieSymbol,0)+1,1); if((StringFind(strCall,strSerieSymbol,0)+1)==StringLen(strCall)) strReturn="A"; if(StringFind(strPut,strSerieSymbol,0)>=0) strReturn=StringSubstr(strPut,StringFind(strPut,strSerieSymbol,0)+1,1); if((StringFind(strPut,strSerieSymbol,0)+1)==StringLen(strPut)) strReturn="M"; return strReturn; } //+------------------------------------------------------------------+ //| Ativo subjacente da opção | //+------------------------------------------------------------------+ string OptionBasis(const string strSymbol) { string strReturn=StringSubstr(SymbolInfoString(strSymbol,SYMBOL_ISIN),2,4); if(StringSubstr(SymbolInfoString(strSymbol, SYMBOL_ISIN), 6, 1)=="9") { strReturn+="11"; } else { strReturn+=StringSubstr(SymbolInfoString(strSymbol,SYMBOL_ISIN),6,1); } return strReturn; } //+------------------------------------------------------------------+ //| Ativo subjacente da opção | //+------------------------------------------------------------------+ double SymbolPrice(const string SYMBOL, const CalcMode CALCMODE) { double result = 0.0; switch(CALCMODE) { case Last: return(SymbolInfoDouble(SYMBOL,SYMBOL_LAST)); break; case VWAP: return(SymbolInfoDouble(SYMBOL,SYMBOL_SESSION_AW)); break; case Median: return(TrueMedian(SymbolInfoDouble(SYMBOL,SYMBOL_BID),SymbolInfoDouble(SYMBOL,SYMBOL_ASK),SymbolInfoDouble(SYMBOL,SYMBOL_LAST))); break; case AskBidWatch: return(SymbolInfoDouble(SYMBOL,SYMBOL_ASK)+SymbolInfoDouble(SYMBOL,SYMBOL_BID))/2; break; } return(result); } double TrueMedian(double first, double second,double third) { SORT(first,second,third); return((third<=0.0)?0.0:((second<=0.0)?third:((first<=0.0)?((third+second)/2.0):second))); } //+------------------------------------------------------------------+ //| Preço da Última Operação | //+------------------------------------------------------------------+ double lastDealPrice(const string strSymbol) { HistorySelect(0,TimeCurrent()); double dbPriceReturn=0.0; ulong ulDealTicket; for(int i=(HistoryDealsTotal()-1);i>=0;i--) { ulDealTicket=HistoryDealGetTicket(i); dbPriceReturn=HistoryDealGetDouble(ulDealTicket,DEAL_PRICE); if(HistoryDealGetString(ulDealTicket,DEAL_SYMBOL)==strSymbol) return(dbPriceReturn); } return(NULL); } //+------------------------------------------------------------------+ //| Preço da Opção por A.A. | //+------------------------------------------------------------------+ double OptionPrice(const string strOption) { double z=(SymbolInfoInteger(strOption,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?1.0:-1.0); long t=(SymbolInfoInteger(strOption,SYMBOL_EXPIRATION_TIME)-TimeCurrent())/86400; long t0=(inpExpirationDI-TimeCurrent())/86400; double r=inpr_0/100; double S=SymbolPrice(OptionBasis(strOption),inpCalcMode); double K=SymbolInfoDouble(strOption,SYMBOL_OPTION_STRIKE); return double (1.0/2.0)*MathSqrt(MathPow(K-S,2.0)+4.0*(double)t/(double)t0*MathPow(r*S,2.0))-z*(K-S)/2.0; } //+------------------------------------------------------------------+