346 lines
30 KiB
MQL5
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|