OptionsMap/OptionsMap.mq5
super.admin 7379123c9c convert
2025-05-30 16:14:59 +02:00

346 lines
30 KiB
MQL5

//+------------------------------------------------------------------+
//| OptionsMap.mq5 |
//| Allan |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#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
DWAP // Daily Weighted Average Price
};
enum ENUM_ShowGraph
{
showBidAsk, // Bid and Ask
showLast, // Last
showMedian, // Median
showBidAskHalf,// (Bid+Ask)/2
showAll, // Show All
showNone // OPM only
};
enum ENUM_Rights
{
rightPUT, // PUT's
rightCALL, // CALL's
//rightBoth // Both
} ;
struct sOption
{
string strSymbol;
ENUM_SYMBOL_OPTION_RIGHT enRight;
double dbK;
double dbP;
double dbC;
ulong dtExpiration;
ulong dtLastDeal;
double dbBid;
double dbAsk;
double dbPrice;
};
//+------------------------------------------------------------------+
//| Globals |
//+------------------------------------------------------------------+
sOption arrBruteOptions[];
//+------------------------------------------------------------------+
//| Expert input values |
//+------------------------------------------------------------------+
sinput datetime inExpiration; // Expiração:
sinput ENUM_Rights inRight=rightCALL; // Opções do Tipo:
sinput double inR=10.75; // Retorno Referência (% a.a.):
sinput ENUM_ShowGraph inShowGraph=showMedian; // Preços do gráfico:
sinput int inFrequency=3; // Frequência de execução (s):
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EA();
EventSetTimer(inFrequency);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
EA();
}
//+------------------------------------------------------------------+
//| EA function |
//+------------------------------------------------------------------+
void EA()
{
ObjectDelete(0,"OptionHunter_Graph");
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].dbK=arrBruteOptions[s].dbK;
arrOptions[i].dbC=arrBruteOptions[s].dbC;
arrOptions[i].dbP=arrBruteOptions[s].dbP;
arrOptions[i].dbBid=arrBruteOptions[s].dbBid;
arrOptions[i].dbAsk=arrBruteOptions[s].dbAsk;
arrOptions[i].dbPrice=arrBruteOptions[s].dbPrice;
}
double _T=0.0;
double _Z=0.0;
double _S=SymbolInfoDouble(_Symbol,SYMBOL_LAST);
double K[];
double Bid[];
double Ask[];
double Last[];
double BidAskHalf[];
double Med[];
double X[];
ArrayResize(K,ArraySize(arrOptions));
ArrayResize(Bid,ArraySize(arrOptions));
ArrayResize(Ask,ArraySize(arrOptions));
ArrayResize(Last,ArraySize(arrOptions));
ArrayResize(BidAskHalf,ArraySize(arrOptions));
ArrayResize(Med,ArraySize(arrOptions));
ArrayResize(X,ArraySize(arrOptions));
for(int i=0;i<ArraySize(arrOptions);i++)
{
K[i]=arrOptions[i].dbK;
Bid[i]=arrOptions[i].dbBid; //SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_BID);
Ask[i]=arrOptions[i].dbAsk; //SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_ASK);
Last[i]=arrOptions[i].dbPrice; //SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_LAST);
BidAskHalf[i]=(arrOptions[i].dbBid+arrOptions[i].dbAsk)/2.0; //(SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_BID)+SymbolInfoDouble(arrOptions[i].strSymbol,SYMBOL_ASK))/2.0;
Med[i]=SymbolPrice(arrOptions[i].strSymbol, Median);
_T = MathMax(0.0,( SymbolInfoInteger(arrOptions[i].strSymbol,SYMBOL_EXPIRATION_TIME)-SymbolInfoInteger(_Symbol,SYMBOL_TIME) ) / (86400.0 * 365.0) );
_Z = (arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_CALL?1.0:(arrOptions[i].enRight==SYMBOL_OPTION_RIGHT_PUT?-1.0:0.0));
X[i]=(1.0/2.0)*sqrt(pow(K[i]-_S,2.0)+4*_T*pow(inR/100*_S,2.0))-_Z*(K[i]-_S)/2.0;
}
CGraphic graphic;
graphic.Create(0,"OptionHunter_Graph",0,0,25,(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS),(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS));
graphic.XAxis().NameSize(12);
graphic.XAxis().Name("Strike (K)");
graphic.XAxis().ValuesFormat("%.2f");
graphic.YAxis().NameSize(12);
graphic.YAxis().Name("Premium (X)");
graphic.YAxis().ValuesFormat("%.2f");
if((inShowGraph==showAll)||(inShowGraph==showBidAsk))
{
CCurve *CCurveAsk = graphic.CurveAdd(K,Ask,clrBlue,CURVE_POINTS,"Ask");
CCurveAsk.PointsType(POINT_HORIZONTAL_DASH);
CCurveAsk.PointsSize(4);
CCurveAsk.PointsFill(true);
CCurve *CCUrveBid = graphic.CurveAdd(K,Bid,clrRed,CURVE_POINTS,"Bid");
CCUrveBid.PointsType(POINT_HORIZONTAL_DASH);
CCUrveBid.PointsSize(4);
CCUrveBid.PointsFill(true);
}
if((inShowGraph==showAll)||(inShowGraph==showBidAskHalf))
{
CCurve *CCurveLast = graphic.CurveAdd(K,BidAskHalf,clrOrange,CURVE_POINTS,"(Bid+Ask)/2");
CCurveLast.PointsType(POINT_CIRCLE);
CCurveLast.PointsSize(4);
CCurveLast.PointsFill(false);
}
if((inShowGraph==showAll)||(inShowGraph==showLast))
{
CCurve *CCurveLast = graphic.CurveAdd(K,Last,clrGreen,CURVE_POINTS,"Last");
CCurveLast.PointsType(POINT_CIRCLE);
CCurveLast.PointsSize(4);
CCurveLast.PointsFill(false);
}
if((inShowGraph==showAll)||(inShowGraph==showMedian))
{
CCurve *CCurveMed = graphic.CurveAdd(K,Med,clrPurple,CURVE_POINTS,"Median");
CCurveMed.PointsType(POINT_CIRCLE);
CCurveMed.PointsSize(8);
CCurveMed.PointsFill(false);
}
CCurve *CCurveOPM = graphic.CurveAdd(K,X,clrMidnightBlue,CURVE_LINES,"OPM");
CCurveOPM.Color(clrFuchsia);
CCurveOPM.LinesSmooth(true);
double Sx[2]={_S,_S};
double Sxmax = 0.0;//MathMax(Ask[0],Ask[ArraySize(Ask)-1]);
for(int i=0;i<ArraySize(Ask);i++)
{
if(inShowGraph==showAll) Sxmax=MathMax(MathMax(MathMax(MathMax(Sxmax,Bid[i]),Ask[i]),Last[i]),X[i]);
if(inShowGraph==showBidAsk) Sxmax=MathMax(MathMax(Sxmax,Bid[i]),Ask[i]);
if(inShowGraph==showBidAskHalf) Sxmax=MathMax(Sxmax,(Bid[i]+Ask[i])/2.0);
if(inShowGraph==showLast) Sxmax=MathMax(Sxmax,Last[i]);
if(inShowGraph==showMedian) Sxmax=MathMax(Sxmax,Med[i]);
if(inShowGraph==showNone) Sxmax=MathMax(Sxmax,X[i]);
}
double Sy[2]={0.0,Sxmax};
CCurve *CCurveS = graphic.CurveAdd(Sx,Sy,clrGreenYellow,CURVE_STEPS,_Symbol);
graphic.CurvePlotAll();
graphic.Update();
ChartSetInteger(0,CHART_SHOW_DATE_SCALE,0);
ChartSetInteger(0,CHART_SHOW_PRICE_SCALE,0);
Comment(StringFormat("S=%.2f",
_S
)
);
}
//+------------------------------------------------------------------+
//| Carrega a Matriz de Opções (Bruta) |
//+------------------------------------------------------------------+
void LoadBruteOptions()
{
string strISIN = SymbolInfoString(_Symbol, SYMBOL_ISIN);
ArrayFree(arrBruteOptions);
ZeroMemory(arrBruteOptions);
for(int i=0;i<SymbolsTotal(false);i++)
{
if(
(SymbolInfoDouble(SymbolName(i,false),SYMBOL_OPTION_STRIKE)>(SymbolInfoDouble(_Symbol,SYMBOL_LAST)*(1-0.25)))
&&(SymbolInfoDouble(SymbolName(i,false),SYMBOL_OPTION_STRIKE)<(SymbolInfoDouble(_Symbol,SYMBOL_LAST)*(1+0.25)))
&&(int(SymbolInfoInteger(SymbolName(i,false),SYMBOL_EXPIRATION_TIME)/86400.0)==int(inExpiration)/86400.0)
//&&((SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL)||(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT))
//&&(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT)
//&&(SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL)
//&&(SymbolInfoInteger(SymbolName(i,false),SYMBOL_EXPIRATION_TIME)>D'2024.10.03 00:00:00')
//&&(SymbolInfoInteger(SymbolName(i,false),SYMBOL_EXPIRATION_TIME)<D'2024.10.05 23:59:59')
//&&(StringLen(SymbolName(i,false))==8)
&&((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))))
)
{
if(
//(inRight==rightBoth)
((inRight==rightCALL)&&((ENUM_SYMBOL_OPTION_RIGHT)SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_CALL))
||((inRight==rightPUT)&&((ENUM_SYMBOL_OPTION_RIGHT)SymbolInfoInteger(SymbolName(i,false),SYMBOL_OPTION_RIGHT)==SYMBOL_OPTION_RIGHT_PUT))
)
// rightPUT, // PUT's
// rightCALL, // CALL's
// rightBoth // Both
{
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);
arrBruteOptions[ArraySize(arrBruteOptions)-1].dbBid=SymbolInfoDouble(SymbolName(i,false),SYMBOL_BID);
arrBruteOptions[ArraySize(arrBruteOptions)-1].dbAsk=SymbolInfoDouble(SymbolName(i,false),SYMBOL_ASK);
arrBruteOptions[ArraySize(arrBruteOptions)-1].dbPrice=SymbolInfoDouble(SymbolName(i,false),SYMBOL_LAST);
}
}
}
}
//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+
//| Symbol Price |
//+------------------------------------------------------------------+
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;
}
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")
||(StringSubstr(SymbolInfoString(strSymbol, SYMBOL_ISIN), 6, 1)=="C")
)
{
strReturn+="11";
}
else
{
strReturn+=StringSubstr(SymbolInfoString(strSymbol,SYMBOL_ISIN),6,1);
}
return strReturn;
}
//+------------------------------------------------------------------+