OptionSniffer/OptionSniffer.mq5

986 lines
100 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:15:01 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| OptionSniffer.mq5 |
//| Arthur Albano |
//| https://www.mql5.com/en/users/arthuralbano/ |
//+------------------------------------------------------------------+
#include <Graphics\Graphic.mqh>
#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<EFBFBD>lculo:
sinput datetime inpMaxExpiration=D'2023.12.31 23:00:00';//M<EFBFBD>xima expira<EFBFBD><EFBFBD>o:
sinput int inpSecondPlane=5;//Atualiza<EFBFBD><EFBFBD>es em segundo plano (s):
sinput group "Ativo";
sinput string inpNextCall="";//Rolar Call para:
sinput string inpNextPut="";//Rolar Put para:
sinput string inpBlackList="";//Op<EFBFBD><EFBFBD>es para ignorar:
sinput group "Options";
sinput showSerie inpShowSerie=Next;//S<EFBFBD>rie:
sinput bool inpShowNegativeDeltaX=true;//Mostrar com diferen<EFBFBD>a de pr<EFBFBD>mios negativo:
sinput bool inpBreakMinorK=true;//Mostrar com ponto de equilibrio menor que atual:
sinput bool inpPlotGraph=false;//Modo Gr<EFBFBD>fico ?
sinput double inpFaixaK=100.0;//Faixa de Strikes (%):
sinput group "Option Price Model";
sinput datetime inpExpirationDI=D'2024.01.24 23:59';//Expira<EFBFBD><EFBFBD>o DI:
sinput double inpr_0=13.625;//<EFBFBD>ndice DI:
//sinput datetime inpNextExpiration=D'2023.11.18 23:59';//Pr<EFBFBD>ximo Exerc<EFBFBD>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<EFBFBD> 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<EFBFBD><EFBFBD>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<ArraySize(arrBruteOptions);i++)
{
vSort[i,0]=(arrBruteOptions[i].dtExpiration*1000000)+(arrBruteOptions[i].enRight*100000)+StringToInteger(DoubleToString(arrBruteOptions[i].dbK*1000,0));
vSort[i,1]=i;
}
ArraySort(vSort);
int s=0;
sOption arrOptions[];
ArrayResize(arrOptions,ArraySize(arrBruteOptions));
for(int i=0;i<ArraySize(arrOptions);i++)
{
s=(int)vSort[i,1];
arrOptions[i].enRight=arrBruteOptions[s].enRight;
arrOptions[i].strSymbol=arrBruteOptions[s].strSymbol;
arrOptions[i].dtExpiration=arrBruteOptions[s].dtExpiration;
arrOptions[i].dtLastDeal=arrBruteOptions[s].dtLastDeal;
arrOptions[i].dbK=arrBruteOptions[s].dbK;
arrOptions[i].dbC=arrBruteOptions[s].dbC;
arrOptions[i].dbP=arrBruteOptions[s].dbP;
}
double dbB=0.0;
double dbLastPremium=lastDealPrice(_Symbol);
double dbS=0.0;
double dbE=0.0;
double dbY=0.0;
double dbYSum=0.0;
double dbYperMonth=0.0;
long lDaysToExpirate=0;
ulong ulPositionTicket=0;
for(int i=0;i<PositionsTotal();i++)
{
ulPositionTicket=PositionGetTicket(i);
if(PositionGetSymbol(i)==_Symbol)
{
dbB=(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL?SymbolInfoDouble(_Symbol,SYMBOL_OPTION_STRIKE)+PositionGetDouble(POSITION_PRICE_OPEN):SymbolInfoDouble(_Symbol,SYMBOL_OPTION_STRIKE)-PositionGetDouble(POSITION_PRICE_OPEN));
}
}
ulong ulHistoryDealTicket=0;
if(dbB==0)
{
for(int i=(HistoryDealsTotal()-1);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<ArraySize(arrOptions);i++)
{
if(
(StringSubstr(arrOptions[i].strSymbol,4,1)==(inpShowSerie==Current?StringSubstr(_Symbol,4,1):(inpShowSerie==Next?nextOptionSerie(StringSubstr(_Symbol,4,1)):nextOptionSerie(nextOptionSerie(StringSubstr(_Symbol,4,1))))))
// &&(arrOptions[i].dbK>(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<EFBFBD><EFBFBD>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<ArraySize(arrOptions);i++)
{
if(
(StringSubstr(arrOptions[i].strSymbol,4,1)==(inpShowSerie==Current?StringSubstr(_Symbol,4,1):(inpShowSerie==Next?nextOptionSerie(StringSubstr(_Symbol,4,1)):nextOptionSerie(nextOptionSerie(StringSubstr(_Symbol,4,1))))))
&&(((arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbC:arrOptions[i].dbP)-SymbolPrice(_Symbol,inpCalcMode)>=0.0)||inpShowNegativeDeltaX)
&&((arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?arrOptions[i].dbK+arrOptions[i].dbC>dbB:arrOptions[i].dbK-arrOptions[i].dbP<dbB)||(inpBreakMinorK))
)
{
ObjectSetDouble(0,"OptionSniffer_Premium",OBJPROP_PRICE,SymbolPrice(_Symbol,inpCalcMode));
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(
(arrOptions[i].dbK>(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;i<HistoryDealsTotal();i++)
{
ulHistoryDealTicket=HistoryDealGetTicket(i);
if(
((HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL)==_Symbol)
||(OptionBasis(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL))==_Symbol))
&&(SymbolInfoDouble(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL),SYMBOL_OPTION_STRIKE)>0.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;i<PositionsTotal();i++)
{
ulPositionTicket=PositionGetTicket(i);
if(SymbolInfoInteger(PositionGetSymbol(i),SYMBOL_EXPIRATION_TIME)>0)
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<EFBFBD>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<00>o <00> uma op<00><00>o de compra (CALL)!";
}
}
else
{
strComment+="Erro: "+inpNextCall+" n<00>o <00> Op<00><00>o!\n\n";
}
}
else
{
//-------------------------------------------------------------------------------------------------------------------------------------------------Roll Call para a Ordem
string strSymbolOrder="";
ulong ulOrderTicket=0;
for(int i=0;i<OrdersTotal();i++)
{
ulOrderTicket=OrderGetTicket(i);
if(
(OptionBasis(OrderGetString(ORDER_SYMBOL))==_Symbol)
&&(SymbolInfoInteger(OrderGetString(ORDER_SYMBOL),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL)
&&(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_LIMIT)
)
{
strSymbolOrder=OrderGetString(ORDER_SYMBOL);
ArrayResize(arrDealsSim,ArraySize(arrDealsSim)+1);
p=ArraySize(arrDealsSim);p--;
arrDealsSim[p].lPositionID=0;
arrDealsSim[p].strSymbol=strSymbolOrder;
arrDealsSim[p].dbVolume=-1.0;
arrDealsSim[p].dtTime=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME)+TimeCurrent())/2;
arrDealsSim[p].enType=DEAL_TYPE_SELL;
arrDealsSim[p].dbPrice=SymbolInfoDouble(strSymbolOrder,SYMBOL_OPTION_STRIKE)+OrderGetDouble(ORDER_PRICE_OPEN);
arrDealsSim[p].lTicket=0;
//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))));
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------Roll Call para o Symbol calculado
if(strSymbolOrder.Length()==0)
{
int iDealB=0;
for(int i=(ArraySize(arrDealsSim)-1);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)<D'2022.12.31 23:00:00')
)
{
arrDealsSim[p].lPositionID=0;
arrDealsSim[p].strSymbol=arrOptions[i].strSymbol;
arrDealsSim[p].dbVolume=0.0;
arrDealsSim[p].dtTime=(SymbolInfoInteger(arrDealsSim[p].strSymbol,SYMBOL_EXPIRATION_TIME)+TimeCurrent())/2;
//arrDealsSim[p].dtTime=TimeCurrent();
arrDealsSim[p].enType=DEAL_TYPE_SELL;
arrDealsSim[p].dbPrice=SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_OPTION_STRIKE)+arrOptions[i].dbC;
arrDealsSim[p].lTicket=0;
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))));
}
}
}
}
ObjectsDeleteAll(0,"OptionSniffer");
string strObjectName="";
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+" OPM",OBJ_ARROW_DOWN,0,arrDealsSim[p].dtTime,SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE)+OptionPrice(arrDealsSim[p].strSymbol));ObjectSetInteger(0,strObjectName+" OPM",OBJPROP_COLOR,clrRed);
if(StringLen(inpNextPut)>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<00>o <00> uma op<00><00>o de venda (PUT)!";
}
}
else
{
strComment+="Erro: "+inpNextPut+" n<00>o <00> Op<00><00>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)<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].dbP>=SymbolPrice(arrDealsSim[iDealB].strSymbol,inpCalcMode))
//&&(SymbolInfoInteger(arrOptions[i].strSymbol,SYMBOL_EXPIRATION_TIME)<D'2022.12.31 23:00:00')
)
{
arrDealsSim[p].lPositionID=0;
arrDealsSim[p].strSymbol=arrOptions[i].strSymbol;
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(arrOptions[i].strSymbol,SYMBOL_OPTION_STRIKE)-arrOptions[i].dbP;
arrDealsSim[p].lTicket=0;
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))));
}
}
}
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,clrRed);
ObjectCreate(0,strObjectName+" OPM",OBJ_ARROW_UP,0,arrDealsSim[p].dtTime,SymbolInfoDouble(arrDealsSim[p].strSymbol,SYMBOL_OPTION_STRIKE)-OptionPrice(arrDealsSim[p].strSymbol));ObjectSetInteger(0,strObjectName+" OPM",OBJPROP_COLOR,clrBlue);
strObjectName="";
ulong ulOrderTicket=0;
for(int i=0;i<ArraySize(arrDealsSim);i++)
{
strObjectName=StringFormat( "OptionSniffer #%.0f %s %.0f %s at %.4f",
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,
(arrDealsSim[i].enType==DEAL_TYPE_BUY?OBJ_ARROW_BUY:OBJ_ARROW_SELL),
0,
arrDealsSim[i].dtTime,
arrDealsSim[i].dbPrice
);
for(int j=0;j<PositionsTotal();j++)
{
ulPositionTicket=PositionGetTicket(j);
if(PositionGetSymbol(j)==arrDealsSim[i].strSymbol)
{
if(SymbolInfoInteger(arrDealsSim[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<00><00>o no vencimento pelo STRIKE.\n";
for(int i=0;i<ArraySize(arrDealsSim);i++)
{
if(SymbolInfoDouble(arrDealsSim[i].strSymbol,SYMBOL_OPTION_STRIKE)>0.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<00><00>o no vencimento pelo STRIKE.\n";
for(int i=0;i<ArraySize(arrDealsSim);i++)
{
if(SymbolInfoDouble(arrDealsSim[i].strSymbol,SYMBOL_OPTION_STRIKE)>0.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;i<ArraySize(arrOptions);i++)
{
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;
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)
);
}
}
StringReplace(strFile,".",",");
string strFileName=_Symbol+".csv";
int iHandle=FileOpen(strFileName,FILE_WRITE|FILE_CSV);
FileWrite(iHandle,strFile);
FileClose(iHandle);
Comment(strStatus+"\n"+strComment);
}
//+------------------------------------------------------------------+
//| Converte C<EFBFBD>digo ISIN para Symbol |
//+------------------------------------------------------------------+
string ISINtoSymbol(const string strISIN)
{
string strSymbol=StringSubstr(strISIN,2,4);
if(StringSubstr(strISIN,9,2)=="PR") strSymbol+="4";
if(StringSubstr(strISIN,9,2)=="OR") strSymbol+="3";
if(StringSubstr(strISIN,9,2)=="00") strSymbol+="9";
return strSymbol;
}
//+------------------------------------------------------------------+
//| Carrega a Matriz de Op<EFBFBD><EFBFBD>es (Bruta) |
//+------------------------------------------------------------------+
void LoadBruteOptions()
{
string strISIN = SymbolInfoString(_Symbol, SYMBOL_ISIN);
ArrayFree(arrBruteOptions);
ZeroMemory(arrBruteOptions);
strStatus="Carregando op<00><00>es....\n";
Comment(strStatus+strComment);
for(int i=0;i<SymbolsTotal(false);i++)
{
if(
(SymbolInfoDouble(SymbolName(i,false),SYMBOL_OPTION_STRIKE)>0.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)<inpMaxExpiration)
&&(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<EFBFBD>xima s<EFBFBD>ria da Op<EFBFBD><EFBFBD>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<EFBFBD><EFBFBD>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<EFBFBD><EFBFBD>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<EFBFBD>o da <EFBFBD>ltima Opera<EFBFBD><EFBFBD>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<EFBFBD>o da Op<EFBFBD><EFBFBD>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;
}
//+------------------------------------------------------------------+