OptionConvert/OptionConvert.mq5
super.admin 624728a9e9 convert
2025-05-30 16:14:43 +02:00

279 lines
24 KiB
MQL5

//+------------------------------------------------------------------+
//| OptionConvert.mq5 |
//| Copyright 2022, Allan Serotini |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#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
};
struct sOption
{
string strSymbol;
ENUM_SYMBOL_OPTION_RIGHT enRight;
double dbK;
double dbP;
double dbC;
ulong dtExpiration;
ulong dtLastDeal;
};
//+------------------------------------------------------------------+
//| Entradas |
//+------------------------------------------------------------------+
sinput group "Globais";
sinput CalcMode inpCalcMode=Median;// Modo de Cálculo:
sinput datetime inpMaxExpiration=D'2022.12.31 23:00:00';//Máxima expiração:
sinput int inpSecondPlane=5;//Atualizações em segundo plano (s):
sinput string inpSymbolConvert="BOVA11";//Converter posição para o Símbolo:
sinput string inpSymbolToConvert="";
//+------------------------------------------------------------------+
//| Globais |
//+------------------------------------------------------------------+
string strStatus="";
string strComment="";
sOption arrBruteOptions[];//Usado como basse para carregar o arrOptions ( localmente em EA() ) já ordenado
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
LoadBruteOptions();
EventSetTimer(1);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
EA();
}
//+------------------------------------------------------------------+
//| Função Principal |
//+------------------------------------------------------------------+
void EA()
{
if(SymbolInfoInteger(_Symbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT)
{
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;
}
strComment="Symbol Q K X B Q.K Q.X Q.B Caixa Break Saldo K/S\n";
double dbEquivalentK=0.0;
double dbQxK=0.0;
double dbQxX=0.0;
double dbQxB=0.0;
ulong ulPositionTicket=0;
for(int i=0;i<PositionsTotal();i++)
{
ulPositionTicket=PositionGetTicket(i);
if(PositionGetSymbol(i)==_Symbol)
{
dbEquivalentK=SymbolPrice(inpSymbolConvert,inpCalcMode)*SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)/SymbolPrice(OptionBasis(_Symbol),inpCalcMode);
dbQxK=SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)*PositionGetDouble(POSITION_VOLUME);
//dbQxX=PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
dbQxX=SymbolPrice(PositionGetSymbol(i),inpCalcMode)*PositionGetDouble(POSITION_VOLUME);
dbQxB=(SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)-SymbolPrice(PositionGetSymbol(i),inpCalcMode))*PositionGetDouble(POSITION_VOLUME);
strComment+=StringFormat("%8s %4.0f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %.4f (K=%.2f)",
PositionGetSymbol(i),
PositionGetDouble(POSITION_VOLUME),
SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE),
//PositionGetDouble(POSITION_PRICE_OPEN),
SymbolPrice(PositionGetSymbol(i),inpCalcMode),
SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)-SymbolPrice(PositionGetSymbol(i),inpCalcMode),
SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)*PositionGetDouble(POSITION_VOLUME),
SymbolPrice(PositionGetSymbol(i),inpCalcMode)*PositionGetDouble(POSITION_VOLUME),
dbQxB,
SymbolInfoDouble(PositionGetSymbol(i),SYMBOL_OPTION_STRIKE)/SymbolPrice(OptionBasis(_Symbol),inpCalcMode),
dbEquivalentK
);
break;
}
}
double dbQ=0.0;
double dbCaixa=0.0;
double dbBreak=0.0;
strComment+="\n";
for(int i=0;i<ArraySize(arrOptions);i++)
{
dbQ=NormalizeDouble(dbQxK/arrOptions[i].dbK,0);
dbCaixa=(dbQ*arrOptions[i].dbP)-dbQxX;
dbBreak=dbQxB-(dbQ*(arrOptions[i].dbK-arrOptions[i].dbP));
if(
(SymbolInfoInteger(arrOptions[i].strSymbol,SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT)
&&( ((dbBreak)>0.0)||(dbCaixa>0.0) )
//&&(arrOptions[i].dbK>=dbEquivalentK)
//&&(arrOptions[i].dbP>0.0)
&&((StringLen(inpSymbolToConvert)>0?inpSymbolToConvert==arrOptions[i].strSymbol:true))
)
{
strComment+=StringFormat("%8s %4.0f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %.4f\n",
arrOptions[i].strSymbol,
dbQ,
arrOptions[i].dbK,
arrOptions[i].dbP,
arrOptions[i].dbK-arrOptions[i].dbP,
dbQ*arrOptions[i].dbK,
dbQ*arrOptions[i].dbP,
dbQ*(arrOptions[i].dbK-arrOptions[i].dbP),
dbCaixa,
dbBreak,
dbCaixa+dbBreak,
arrOptions[i].dbK/SymbolPrice(OptionBasis(arrOptions[i].strSymbol),inpCalcMode)
);
}
}
Comment(strStatus+"\n"+strComment);
}
else
{
Comment("");
}
}
//+------------------------------------------------------------------+
//| Converte Có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ções (Bruta) |
//+------------------------------------------------------------------+
void LoadBruteOptions()
{
string strISIN = SymbolInfoString(inpSymbolConvert, SYMBOL_ISIN);
ArrayFree(arrBruteOptions);
ZeroMemory(arrBruteOptions);
strStatus="Carregando opçõ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(inpSymbolConvert,SYMBOL_ISIN)))||((StringSubstr(SymbolInfoString(SymbolName(i,false),SYMBOL_ISIN),2,5)==StringSubstr(SymbolInfoString(inpSymbolConvert,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);
}
//+------------------------------------------------------------------+
//| 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)));
}
//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+