611 lines
60 KiB
MQL5
611 lines
60 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Stocks.mq5 |
|
|
//| Copyright 2022, MetaQuotes Ltd. |
|
|
//| 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
|
|
};
|
|
enum GridLoweLimitType
|
|
{
|
|
MinHistoric,//Mínima histórica
|
|
MinHistoric_Minus50pcToZero,//Mínima histórica menos 50% até Zero
|
|
One_Mili,//0,001
|
|
One_Cents,//0,01
|
|
Two_Half_Cents,//0,025
|
|
Ten_Cents,//0,1
|
|
One_Money,//1
|
|
Customized//Especificar:
|
|
};
|
|
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 dbYield;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Entradas |
|
|
//+------------------------------------------------------------------+
|
|
sinput group "Setup Financeiro";
|
|
sinput double inpFinancialTicket=100.0;//Ficha financeira (brl):
|
|
sinput double inpBalanceCorrection=0.0;//Correção do Patrimônio (brl):
|
|
sinput group "Análises";
|
|
sinput CalcMode inpCalcMode=Median;//Modo de Cálculo:
|
|
sinput ulong inpRatesQuantidade=52;//Quantidade de dias:
|
|
sinput bool inpLoadGraph=false;//Carrega o gráfico da melhor operação:
|
|
sinput group "Grid";
|
|
sinput bool inpGrid=true;//Mostra Grid?
|
|
sinput bool inpLastPriceToBase;//Ancorar na última operação?
|
|
sinput double inpGridVolume=0.0;//Volume no Grid:
|
|
sinput double inpGridSec=1.0;//Segmentações dos níveis do Grid:
|
|
sinput GridLoweLimitType inpGridLowerType=Ten_Cents;//Limite inferior da grade:
|
|
sinput double inpGridLowerLimit=0.5;//Limite inferior personalizado (brl):
|
|
//+------------------------------------------------------------------+
|
|
//| Variáveis Globais |
|
|
//+------------------------------------------------------------------+
|
|
double gdbBalance=inpBalanceCorrection;//Saldo (brl):
|
|
double gdbEquity=0.0;
|
|
string strComment="";
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
Comment(StringFormat("\nBalancey: %.2f, Equity: %.2f",inpBalanceCorrection,AccountInfoDouble(ACCOUNT_EQUITY)));Sleep(1000);
|
|
EventSetTimer(1);
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
ObjectsDeleteAll(0,"Stocks");
|
|
EventKillTimer();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Timer function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
gdbBalance=inpBalanceCorrection;
|
|
gdbEquity=AccountInfoDouble(ACCOUNT_EQUITY);
|
|
stcDeal arrLostDeals[];
|
|
ArrayResize(arrLostDeals,11);
|
|
/**********************************************************************************
|
|
arrLostDeals[0].strSymbol="GOAU4F";
|
|
arrLostDeals[0].dtTime=D'2022.03.02 13:09:11';
|
|
arrLostDeals[0].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[0].dbVolume=9.0;
|
|
arrLostDeals[0].dbPrice=10.77;
|
|
arrLostDeals[1].strSymbol="GOAU4F";
|
|
arrLostDeals[1].dtTime=D'2022.03.03 00:00:00';
|
|
arrLostDeals[1].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[1].dbVolume=9.0;
|
|
arrLostDeals[1].dbPrice=11.29;
|
|
arrLostDeals[2].strSymbol="B3SA3F";
|
|
arrLostDeals[2].dtTime=D'2022.03.03 00:00:00';
|
|
arrLostDeals[2].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[2].dbVolume=9.0;
|
|
arrLostDeals[2].dbPrice=15.19;
|
|
arrLostDeals[3].strSymbol="B3SA3F";
|
|
arrLostDeals[3].dtTime=D'2022.03.03 00:00:01';
|
|
arrLostDeals[3].enType=DEAL_TYPE_BUY;
|
|
arrLostDeals[3].dbVolume=9.0;
|
|
arrLostDeals[3].dbPrice=14.73;
|
|
arrLostDeals[4].strSymbol="IRBR3F";
|
|
arrLostDeals[4].dtTime=D'2022.03.03 00:00:00';
|
|
arrLostDeals[4].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[4].dbVolume=30.0;
|
|
arrLostDeals[4].dbPrice=3.22;
|
|
arrLostDeals[5].strSymbol="ENJU3F";
|
|
arrLostDeals[5].dtTime=D'2022.03.03 14:54:40';
|
|
arrLostDeals[5].enType=DEAL_TYPE_BUY;
|
|
arrLostDeals[5].dbVolume=35.0;
|
|
arrLostDeals[5].dbPrice=2.9;
|
|
arrLostDeals[6].strSymbol="HASH11";
|
|
arrLostDeals[6].dtTime=D'2022.03.02 13:25:33';
|
|
arrLostDeals[6].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[6].dbVolume=3.0;
|
|
arrLostDeals[6].dbPrice=40.0;
|
|
arrLostDeals[7].strSymbol="HASH11";
|
|
arrLostDeals[7].dtTime=D'2022.03.02 13:25:33';
|
|
arrLostDeals[7].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[7].dbVolume=3.0;
|
|
arrLostDeals[7].dbPrice=40.0;
|
|
arrLostDeals[8].strSymbol="HASH11";
|
|
arrLostDeals[8].dtTime=D'2022.03.03 16:26:05';
|
|
arrLostDeals[8].enType=DEAL_TYPE_BUY;
|
|
arrLostDeals[8].dbVolume=3.0;
|
|
arrLostDeals[8].dbPrice=37.25;
|
|
arrLostDeals[9].strSymbol="CMIN3F";
|
|
arrLostDeals[9].dtTime=D'2022.03.02 13:01:13';
|
|
arrLostDeals[9].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[9].dbVolume=15.0;
|
|
arrLostDeals[9].dbPrice=6.38;
|
|
arrLostDeals[10].strSymbol="CMIN3F";
|
|
arrLostDeals[10].dtTime=D'2022.03.03 13:01:13';
|
|
arrLostDeals[10].enType=DEAL_TYPE_SELL;
|
|
arrLostDeals[10].dbVolume=15.0;
|
|
arrLostDeals[10].dbPrice=6.69;
|
|
********************************************************************************************/
|
|
strComment="";
|
|
double dbExposure=0.0;
|
|
ulong ulPositionTicket=0;
|
|
for(int i=0;i<PositionsTotal();i++)
|
|
{
|
|
ulPositionTicket=PositionGetTicket(i);
|
|
dbExposure+=PositionGetDouble(POSITION_PRICE_OPEN)*PositionGetDouble(POSITION_VOLUME);
|
|
}
|
|
MqlRates arrMqlRatesPositions[];
|
|
stcDeal dealLast;ZeroMemory(dealLast);
|
|
double dbPortfolioReturn=0.0;
|
|
double dbPortfolioRisk=0.0;
|
|
ulPositionTicket=0;
|
|
for(int i=0;i<PositionsTotal();i++)
|
|
{
|
|
ulPositionTicket=PositionGetTicket(i);
|
|
//--Retorno Médio
|
|
CopyRates(PositionGetSymbol(i),PERIOD_D1,0,(int)inpRatesQuantidade,arrMqlRatesPositions);
|
|
double dbRetornoMedia=0.0;
|
|
for(int j=0;j<ArraySize(arrMqlRatesPositions);j++) if(j>0) dbRetornoMedia+=(arrMqlRatesPositions[j].close-arrMqlRatesPositions[j-1].close)/(2/(1/(arrMqlRatesPositions[j].close)+(1/arrMqlRatesPositions[j-1].close)));
|
|
dbRetornoMedia=dbRetornoMedia/(ArraySize(arrMqlRatesPositions)-1);
|
|
dbPortfolioReturn+=dbRetornoMedia*PositionGetDouble(POSITION_VOLUME)*PositionGetDouble(POSITION_PRICE_OPEN)/gdbBalance;
|
|
//---> Variância
|
|
double dbRetornoVariancia=0.0;
|
|
for(int j=0;j<ArraySize(arrMqlRatesPositions);j++) if(j>0) dbRetornoVariancia+=MathPow(((arrMqlRatesPositions[j].close-arrMqlRatesPositions[j-1].close)/(2/(1/arrMqlRatesPositions[j].close+1/arrMqlRatesPositions[j-1].close)-dbRetornoMedia)),2);
|
|
dbRetornoVariancia=dbRetornoVariancia/(ArraySize(arrMqlRatesPositions)-1);
|
|
dbPortfolioRisk+=(dbRetornoVariancia)*MathPow(PositionGetDouble(POSITION_VOLUME)*PositionGetDouble(POSITION_PRICE_OPEN)/gdbBalance,2);
|
|
}
|
|
MqlRates arrMqlRatesSymbol[];
|
|
CopyRates(_Symbol,PERIOD_D1,0,(int)inpRatesQuantidade,arrMqlRatesSymbol);
|
|
double dbSymbol_r=0.0;
|
|
for(int i=0;i<ArraySize(arrMqlRatesSymbol);i++)if(i>0)dbSymbol_r+=(arrMqlRatesSymbol[i].close-arrMqlRatesSymbol[i-1].close)/(2/(1/(arrMqlRatesSymbol[i].close)+(1/arrMqlRatesSymbol[i-1].close)));
|
|
dbSymbol_r=dbSymbol_r/(ArraySize(arrMqlRatesSymbol)-1);
|
|
double dbSymbol_s=0.0;
|
|
for(int i=0;i<ArraySize(arrMqlRatesSymbol);i++)if(i>0)dbSymbol_s+=MathPow(((arrMqlRatesSymbol[i].close-arrMqlRatesSymbol[i-1].close)/(2/(1/arrMqlRatesSymbol[i].close+1/arrMqlRatesSymbol[i-1].close)-dbSymbol_r)),2);
|
|
dbSymbol_s=dbSymbol_s/(ArraySize(arrMqlRatesSymbol)-1);
|
|
stcDeal arrHistoryDeals[];
|
|
ZeroMemory(arrHistoryDeals);
|
|
int p=0;
|
|
int pos_l=0;
|
|
HistorySelect(0,TimeCurrent());
|
|
ulong ulHistoryDealTicket=0;
|
|
for(int i=0;i<HistoryDealsTotal();i++)
|
|
{
|
|
ulHistoryDealTicket=HistoryDealGetTicket(i);
|
|
if(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL)==_Symbol)
|
|
{
|
|
ArrayResize(arrHistoryDeals,ArraySize(arrHistoryDeals)+1);
|
|
p=ArraySize(arrHistoryDeals);p--;
|
|
arrHistoryDeals[p].lPositionID=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_POSITION_ID);
|
|
arrHistoryDeals[p].strSymbol=HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL);
|
|
arrHistoryDeals[p].enType=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE);
|
|
arrHistoryDeals[p].dtTime=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TIME);
|
|
arrHistoryDeals[p].dbVolume=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_VOLUME);
|
|
arrHistoryDeals[p].dbPrice=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE);
|
|
if(ArraySize(arrLostDeals)>0)
|
|
{
|
|
for(int l=pos_l;l<ArraySize(arrLostDeals);l++)
|
|
{
|
|
if(arrLostDeals[l].strSymbol==_Symbol)
|
|
{
|
|
if(arrLostDeals[l].dtTime<arrHistoryDeals[p].dtTime)
|
|
{
|
|
arrHistoryDeals[p].lPositionID=0;
|
|
arrHistoryDeals[p].strSymbol=arrLostDeals[l].strSymbol;
|
|
arrHistoryDeals[p].enType=arrLostDeals[l].enType;
|
|
arrHistoryDeals[p].dtTime=arrLostDeals[l].dtTime;
|
|
arrHistoryDeals[p].dbVolume=arrLostDeals[l].dbVolume;
|
|
arrHistoryDeals[p].dbPrice=arrLostDeals[l].dbPrice;
|
|
pos_l=l+1; i--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
strComment+="\n";
|
|
strComment+=StringFormat("Portfolio: Balance=%.2f, r=%.2f%%, s=%.2f%%, ld=%.2f%%, dn=%.2f%%\nSymbol: r=%.2f%%, s=%.2f%%, cv=%.5f, vol=%.0f, w=%.2f%%\n",
|
|
gdbBalance,
|
|
100*dbPortfolioReturn,
|
|
100*MathSqrt(dbPortfolioRisk),
|
|
100*dbExposure/gdbBalance,
|
|
100*(gdbBalance-gdbEquity)/gdbBalance,
|
|
100*dbSymbol_r,
|
|
100*MathSqrt(dbSymbol_s),
|
|
MathSqrt(dbSymbol_s)/dbSymbol_r,
|
|
MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode)),
|
|
100*(MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode))*(arrHistoryDeals.Size()>0?arrHistoryDeals[arrHistoryDeals.Size()-1].dbPrice:SymbolPrice(_Symbol,inpCalcMode)))/gdbBalance
|
|
);
|
|
p=0;
|
|
double dbPositionVolume=0.0;
|
|
stcDeal arrSymbolPositions[];
|
|
for(int i=0;i<ArraySize(arrHistoryDeals);i++)
|
|
{
|
|
if(arrHistoryDeals[i].enType==DEAL_TYPE_BUY){dbPositionVolume+=arrHistoryDeals[i].dbVolume;}
|
|
if(arrHistoryDeals[i].enType==DEAL_TYPE_SELL){dbPositionVolume-=arrHistoryDeals[i].dbVolume;}
|
|
if(dbPositionVolume==0.0){ArrayResize(arrSymbolPositions,0);}
|
|
else
|
|
{
|
|
ArrayResize(arrSymbolPositions,ArraySize(arrSymbolPositions)+1);
|
|
p=ArraySize(arrSymbolPositions);p--;
|
|
arrSymbolPositions[p].lPositionID=arrHistoryDeals[i].lPositionID;
|
|
arrSymbolPositions[p].strSymbol=arrHistoryDeals[i].strSymbol;
|
|
arrSymbolPositions[p].enType=arrHistoryDeals[i].enType;
|
|
arrSymbolPositions[p].dtTime=arrHistoryDeals[i].dtTime;
|
|
arrSymbolPositions[p].dbVolume=arrHistoryDeals[i].dbVolume;
|
|
arrSymbolPositions[p].dbPrice=arrHistoryDeals[i].dbPrice;
|
|
}
|
|
}
|
|
strComment+="\n";
|
|
double dbGridBasePrice=0.0;
|
|
if((ArraySize(arrHistoryDeals)>0)&&(inpLastPriceToBase)){dbGridBasePrice=arrHistoryDeals[0].dbPrice;}else{dbGridBasePrice=SymbolPrice(_Symbol,inpCalcMode);};
|
|
p=ArraySize(arrHistoryDeals)-1-ArraySize(arrSymbolPositions);
|
|
if(p>=0)
|
|
{
|
|
strComment+=StringFormat("%2s %s %s %s %6.2f %3.0f",
|
|
"L", //(int)i+1,
|
|
arrHistoryDeals[p].strSymbol,
|
|
StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrHistoryDeals[p].enType),10,5),
|
|
TimeToString(arrHistoryDeals[p].dtTime,TIME_DATE|TIME_MINUTES|TIME_SECONDS),
|
|
arrHistoryDeals[p].dbPrice,
|
|
arrHistoryDeals[p].dbVolume
|
|
);
|
|
dbGridBasePrice=arrHistoryDeals[(arrHistoryDeals.Size()>=3?2:1)].dbPrice;
|
|
strComment+="\n";
|
|
}
|
|
double dbExcessReturn=0.0;
|
|
double dbExposureVolume=0.0;
|
|
for(int i=0;i<ArraySize(arrSymbolPositions);i++)
|
|
{
|
|
if(arrSymbolPositions[i].enType==DEAL_TYPE_BUY){dbExposureVolume+=arrSymbolPositions[i].dbVolume;}
|
|
if(arrSymbolPositions[i].enType==DEAL_TYPE_SELL){dbExposureVolume-=arrSymbolPositions[i].dbVolume;}
|
|
strComment+=StringFormat("%2.0f %s %s %s %6.2f %3.0f %4.0f",
|
|
(int)i+1,
|
|
arrSymbolPositions[i].strSymbol,
|
|
StringSubstr(EnumToString((ENUM_DEAL_TYPE)arrSymbolPositions[i].enType),10,5),
|
|
TimeToString(arrSymbolPositions[i].dtTime,TIME_DATE|TIME_MINUTES|TIME_SECONDS),
|
|
arrSymbolPositions[i].dbPrice,
|
|
arrSymbolPositions[i].dbVolume,
|
|
dbExposureVolume
|
|
);
|
|
if(ArraySize(arrHistoryDeals)>ArraySize(arrSymbolPositions))
|
|
if(i==0)
|
|
{
|
|
dbExcessReturn=100*(arrHistoryDeals[p].dbPrice-arrSymbolPositions[i].dbPrice)/(2/(1/arrHistoryDeals[p].dbPrice+1/arrSymbolPositions[i].dbPrice));
|
|
strComment+=StringFormat(" %5.2f%%",
|
|
dbExcessReturn
|
|
);
|
|
}
|
|
strComment+="\n";
|
|
}
|
|
double dbMax=0.0;
|
|
double dbMin=99999.99;
|
|
stcDeal dealSimulation; ZeroMemory(dealSimulation);
|
|
if(ArraySize(arrHistoryDeals)>0)
|
|
{
|
|
dealSimulation.strSymbol=arrHistoryDeals[ArraySize(arrHistoryDeals)-1].strSymbol;
|
|
dealSimulation.dbPrice=SymbolPrice(dealSimulation.strSymbol,inpCalcMode);
|
|
dealSimulation.dbVolume=(ArraySize(arrHistoryDeals)>0?arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbVolume:MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode)));
|
|
if(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].enType==DEAL_TYPE_BUY)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)>arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_SELL;ObjectCreate(0,"Stocks_SimulationSell",OBJ_ARROW_DOWN,0,TimeLocal(),arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice/(1-(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_COLOR,clrRed);}
|
|
if(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].enType==DEAL_TYPE_BUY)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)<=arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_BUY;ObjectCreate(0,"Stocks_SimulationBuy",OBJ_ARROW_UP,0,TimeLocal(),arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*(1-(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_COLOR,clrBlue);}
|
|
if(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].enType==DEAL_TYPE_SELL)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)>arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice)
|
|
if(dbExposureVolume>0.0){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_SELL;ObjectCreate(0,"Stocks_SimulationSell",OBJ_HLINE,0,0,arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice/(1-(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_COLOR,clrFireBrick);}
|
|
else{dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_BUY;ObjectCreate(0,"Stocks_SimulationBuy",OBJ_HLINE,0,0,arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*(1-(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_COLOR,clrMidnightBlue);}
|
|
if(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].enType==DEAL_TYPE_SELL)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)<=arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_BUY;ObjectCreate(0,"Stocks_SimulationBuy",OBJ_HLINE,0,0,arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*(1-(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_COLOR,clrMidnightBlue);}
|
|
strComment+=StringFormat("%2s %s %s %s %6.2f %3.0f %4.0f %5.2f%%\n",
|
|
"S", //(int)i+1,
|
|
dealSimulation.strSymbol,
|
|
StringSubstr(EnumToString((ENUM_DEAL_TYPE)dealSimulation.enType),10,5),
|
|
TimeToString(TimeLocal(),TIME_DATE|TIME_MINUTES|TIME_SECONDS),
|
|
dealSimulation.dbPrice,
|
|
dealSimulation.dbVolume,
|
|
(dealSimulation.enType==DEAL_TYPE_BUY?dbExposureVolume+dealSimulation.dbVolume:dbExposureVolume-dealSimulation.dbVolume),
|
|
100*(dealSimulation.enType==DEAL_TYPE_BUY?(arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice-dealSimulation.dbPrice)/(2/(1/dealSimulation.dbPrice+1/arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice)):(dealSimulation.dbPrice-arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice)/(2/(1/dealSimulation.dbPrice+1/arrHistoryDeals[ArraySize(arrHistoryDeals)-1].dbPrice)))
|
|
);
|
|
double dbVWAP=0.0;
|
|
ulong iTickCount=0;
|
|
double dbSumVolum=0;
|
|
MqlTick arrMqlTicks[];
|
|
CopyTicks(_Symbol,arrMqlTicks,COPY_TICKS_TRADE,(ulong)(TimeCurrent()-(inpRatesQuantidade*86400))*1000,(uint)TimeCurrent());
|
|
for(int i=0;i<ArraySize(arrMqlTicks);i++)
|
|
if(arrMqlTicks[i].last>0)
|
|
{
|
|
dbMax=MathMax(dbMax,arrMqlTicks[i].last);
|
|
dbMin=MathMin(dbMin,arrMqlTicks[i].last);
|
|
dbVWAP+=arrMqlTicks[i].last*arrMqlTicks[i].volume_real;
|
|
dbSumVolum+=arrMqlTicks[i].volume_real;
|
|
iTickCount++;
|
|
}
|
|
dbVWAP=dbVWAP/dbSumVolum;
|
|
double dbMedian=0.0;
|
|
double arrPrecos[];
|
|
ArrayResize(arrPrecos,ArraySize(arrMqlTicks));
|
|
for(int i=0;i<ArraySize(arrMqlTicks);i++) arrPrecos[i]=arrMqlTicks[i].last;
|
|
ArraySort(arrPrecos);
|
|
dbMedian=(ArraySize(arrPrecos)>0?arrPrecos[ArraySize(arrPrecos)/2]:0.0);
|
|
//strComment+=StringFormat("\nmáx=%.2f (%.2f%%)\nmed=%.2f (%.2f%%), vwap=%.2f (%.2f%%)\nmín=%.2f (%.2f%%)\n",
|
|
// dbMax,
|
|
// 100*(dbMax-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMax+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbMedian,
|
|
// 100*(dbMedian-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMedian+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbVWAP,
|
|
// 100*(dbVWAP-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbVWAP+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbMin,
|
|
// 100*(dbMin-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMin+1/SymbolPrice(_Symbol,inpCalcMode)))
|
|
//);
|
|
//ObjectCreate(0,"Stocks_SymbolVWAP",OBJ_HLINE,0,0,dbVWAP);ObjectSetInteger(0,"Stocks_SymbolVWAP",OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,"Stocks_SymbolVWAP",OBJPROP_COLOR,clrDarkKhaki);
|
|
//ObjectCreate(0,"Stocks_SymbolMin",OBJ_HLINE,0,0,dbMin);ObjectSetInteger(0,"Stocks_SymbolMin",OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,"Stocks_SymbolMin",OBJPROP_COLOR,clrDarkBlue);
|
|
//ObjectCreate(0,"Stocks_SymbolMax",OBJ_HLINE,0,0,dbMax);ObjectSetInteger(0,"Stocks_SymbolMax",OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,"Stocks_SymbolMax",OBJPROP_COLOR,clrFireBrick);
|
|
//strComment+=StringFormat("Impact: d_r=%.4f%%, d_s=%.4f%%, n_ld=%.2f%%",
|
|
// 100*((dbPortfolioReturn+((dbSymbol_r*(MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode)))*SymbolPrice(_Symbol,inpCalcMode))/gdbBalance))-dbPortfolioReturn),
|
|
// 100*MathSqrt(dbPortfolioRisk+(dbSymbol_s*(MathPow(MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode))*SymbolPrice(_Symbol,inpCalcMode)/gdbBalance,2))))-(MathSqrt(dbPortfolioRisk)*100),
|
|
// 100*((dbExposure+(MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode))*SymbolPrice(_Symbol,inpCalcMode)))/gdbBalance)
|
|
//);
|
|
}
|
|
else
|
|
{
|
|
double dbVWAP=0.0;
|
|
ulong iTickCount=0;
|
|
double dbSumVolum=0;
|
|
MqlTick arrMqlTicks[];
|
|
CopyTicks(_Symbol,arrMqlTicks,COPY_TICKS_TRADE,(ulong)(TimeCurrent()-(inpRatesQuantidade*86400))*1000,(uint)TimeCurrent());
|
|
for(int i=0;i<ArraySize(arrMqlTicks);i++)
|
|
if(arrMqlTicks[i].last>0)
|
|
{
|
|
dbMax=MathMax(dbMax,arrMqlTicks[i].last);
|
|
dbMin=MathMin(dbMin,arrMqlTicks[i].last);
|
|
dbVWAP+=arrMqlTicks[i].last*arrMqlTicks[i].volume_real;
|
|
dbSumVolum+=arrMqlTicks[i].volume_real;
|
|
iTickCount++;
|
|
}
|
|
dbVWAP=dbVWAP/dbSumVolum;
|
|
double dbMedian=0.0;
|
|
double arrPrecos[];
|
|
ArrayResize(arrPrecos,ArraySize(arrMqlTicks));
|
|
for(int i=0;i<ArraySize(arrMqlTicks);i++) arrPrecos[i]=arrMqlTicks[i].last;
|
|
ArraySort(arrPrecos);
|
|
dbMedian=(ArraySize(arrPrecos)>0?arrPrecos[ArraySize(arrPrecos)/2]:0.0);
|
|
//strComment+=StringFormat("\nmáx=%.2f (%.2f%%)\nmed=%.2f (%.2f%%), vwap=%.2f (%.2f%%)\nmín=%.2f (%.2f%%)\n",
|
|
// dbMax,
|
|
// 100*(dbMax-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMax+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbMedian,
|
|
// 100*(dbMedian-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMedian+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbVWAP,
|
|
// 100*(dbVWAP-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbVWAP+1/SymbolPrice(_Symbol,inpCalcMode))),
|
|
// dbMin,
|
|
// 100*(dbMin-SymbolPrice(_Symbol,inpCalcMode))/(2/(1/dbMin+1/SymbolPrice(_Symbol,inpCalcMode)))
|
|
//);
|
|
//ObjectCreate(0,"Stocks_SymbolVWAP",OBJ_HLINE,0,0,dbVWAP);ObjectSetInteger(0,"Stocks_SymbolVWAP",OBJPROP_STYLE,STYLE_DOT);ObjectSetInteger(0,"Stocks_SymbolVWAP",OBJPROP_COLOR,clrDarkKhaki);
|
|
}
|
|
ObjectCreate(0,"Stocks_SymbolPrice",OBJ_HLINE,0,0,SymbolPrice(_Symbol,inpCalcMode));ObjectSetInteger(0,"Stocks_SymbolPrice",OBJPROP_STYLE,STYLE_SOLID);ObjectSetInteger(0,"Stocks_SymbolPrice",OBJPROP_COLOR,clrYellow);
|
|
//strComment+="\n";
|
|
if(inpGrid)
|
|
{
|
|
double dbGridLowerLimit=0.0;
|
|
switch(inpGridLowerType)
|
|
{
|
|
case MinHistoric:
|
|
{
|
|
dbGridLowerLimit=9999.99;
|
|
MqlRates arrMqlRatesGrid[];
|
|
CopyRates(_Symbol,PERIOD_D1,0,999999999,arrMqlRatesGrid);
|
|
for(int i=0;i<ArraySize(arrMqlRatesGrid);i++)
|
|
{
|
|
if(dbGridLowerLimit>arrMqlRatesGrid[i].low) dbGridLowerLimit=arrMqlRatesGrid[i].low;
|
|
}
|
|
break;
|
|
}
|
|
case MinHistoric_Minus50pcToZero:
|
|
{
|
|
dbGridLowerLimit=9999.99;
|
|
MqlRates arrMqlRatesGrid[];
|
|
CopyRates(_Symbol,PERIOD_D1,0,999999999,arrMqlRatesGrid);
|
|
for(int i=0;i<ArraySize(arrMqlRatesGrid);i++)
|
|
{
|
|
if(dbGridLowerLimit>arrMqlRatesGrid[i].low) dbGridLowerLimit=arrMqlRatesGrid[i].low;
|
|
}
|
|
dbGridLowerLimit-=(dbGridLowerLimit/2);
|
|
break;
|
|
}
|
|
case One_Mili:
|
|
dbGridLowerLimit=0.001;
|
|
break;
|
|
case One_Cents:
|
|
dbGridLowerLimit=0.01;
|
|
break;
|
|
case Two_Half_Cents:
|
|
dbGridLowerLimit=0.025;
|
|
break;
|
|
case Ten_Cents:
|
|
dbGridLowerLimit=0.1;
|
|
break;
|
|
case One_Money:
|
|
dbGridLowerLimit=1.0;
|
|
break;
|
|
default:
|
|
dbGridLowerLimit=inpGridLowerLimit;
|
|
}
|
|
ObjectsDeleteAll(ChartID(),"Stocks_Grid");
|
|
string strGridObjectName="";
|
|
double dbGridVolume=(inpGridVolume>0.0?inpGridVolume:(ArraySize(arrHistoryDeals)>0?arrHistoryDeals[0].dbVolume:MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode))));
|
|
dbGridVolume=(inpGridSec>0.0?dbGridVolume/inpGridSec:SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN));
|
|
double dbGridExposureVolume=0.0;
|
|
double dbGridExposure=0.0;
|
|
for(double i=dbGridBasePrice;i<(dbGridBasePrice*10.0);i+=(i*((dbGridVolume*dbGridBasePrice)/gdbBalance)))
|
|
{
|
|
strGridObjectName=StringFormat("Stocks_Grid_p%.2f_v%.0f",NormalizeDouble(i,2),dbGridVolume);
|
|
ObjectCreate(0,strGridObjectName,OBJ_HLINE,0,0,i);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_STYLE,STYLE_DASHDOT);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_COLOR,clrDimGray);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_BACK,1);
|
|
}
|
|
for(double i=dbGridBasePrice;i>=dbGridLowerLimit;i-=(i*((dbGridVolume*dbGridBasePrice)/gdbBalance)))
|
|
{
|
|
strGridObjectName=StringFormat("Stocks_Grid_p%.2f_v%.0f",NormalizeDouble(i,2),dbGridVolume);
|
|
ObjectCreate(0,strGridObjectName,OBJ_HLINE,0,0,i);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_STYLE,STYLE_DASHDOT);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_COLOR,clrDimGray);
|
|
ObjectSetInteger(0,strGridObjectName,OBJPROP_BACK,1);
|
|
dbGridExposure+=dbGridVolume*i;
|
|
dbGridExposureVolume+=dbGridVolume;
|
|
}
|
|
//strComment+="GRID:";
|
|
//strComment+=StringFormat("\nbase=%.2f, lim_low=%.4f, v=%.0f\nv_max=%.0f, ld_max=%.2f%%",
|
|
// dbGridBasePrice,
|
|
// dbGridLowerLimit,
|
|
// dbGridVolume,
|
|
// dbGridExposureVolume,
|
|
// 100*dbGridExposure/gdbBalance
|
|
//);
|
|
if(dbGridExposure>gdbBalance){strComment+=" [ FAIL !!! ]";ObjectsDeleteAll(ChartID(),"Stocks_Grid");};
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Best Deal
|
|
stcDeal bestDeal;
|
|
ZeroMemory(bestDeal);
|
|
string strSymbol="";
|
|
double dbYield=0.0;
|
|
double dbPreviousYield=-9999.0;
|
|
for(int i=0;i<SymbolsTotal(true);i++)
|
|
{
|
|
strSymbol=SymbolName(i,true);
|
|
if(
|
|
(SymbolInfoDouble(strSymbol,SYMBOL_ASK)>0.0)
|
|
&&(SymbolInfoDouble(strSymbol,SYMBOL_BID)>0.0)
|
|
)
|
|
{
|
|
stcDeal lastDeal = getLastDeal(strSymbol);
|
|
if(lastDeal.dbPrice>0.0)
|
|
{
|
|
if(lastDeal.enType==DEAL_TYPE_SELL)
|
|
{
|
|
dbYield=(lastDeal.dbPrice-SymbolPrice(strSymbol,inpCalcMode))/(2/(1/lastDeal.dbPrice+1/SymbolInfoDouble(strSymbol,SYMBOL_BID)));
|
|
}
|
|
else
|
|
{
|
|
dbYield=(SymbolPrice(strSymbol,inpCalcMode)-lastDeal.dbPrice)/(2/(1/lastDeal.dbPrice+1/SymbolInfoDouble(strSymbol,SYMBOL_ASK)));
|
|
}
|
|
if(dbPreviousYield<=dbYield)
|
|
{
|
|
dbPreviousYield=dbYield;
|
|
bestDeal.strSymbol=strSymbol;
|
|
bestDeal.dbYield=dbPreviousYield;
|
|
if(lastDeal.enType==DEAL_TYPE_SELL)
|
|
{
|
|
bestDeal.enType=DEAL_TYPE_BUY;
|
|
bestDeal.dbPrice=SymbolInfoDouble(bestDeal.strSymbol,SYMBOL_ASK);
|
|
bestDeal.dbVolume=lastDeal.dbVolume;
|
|
}
|
|
else
|
|
{
|
|
bestDeal.enType=DEAL_TYPE_SELL;
|
|
bestDeal.dbPrice=SymbolInfoDouble(bestDeal.strSymbol,SYMBOL_BID);
|
|
bestDeal.dbVolume=MathRound(inpFinancialTicket/bestDeal.dbPrice);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(
|
|
(StringLen(bestDeal.strSymbol)>0)
|
|
)
|
|
{
|
|
if(inpLoadGraph) ChartSetSymbolPeriod(ChartID(),bestDeal.strSymbol,ChartPeriod(0));
|
|
strComment+=StringFormat("\n%s %.0f %s %.2f (%.2f%%)",
|
|
StringSubstr(EnumToString((ENUM_DEAL_TYPE)bestDeal.enType),10,4),
|
|
bestDeal.dbVolume,
|
|
bestDeal.strSymbol,
|
|
bestDeal.dbPrice,
|
|
100*bestDeal.dbYield
|
|
);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Best Deak (End)
|
|
for(int i=0;i<PositionsTotal();i++)
|
|
{
|
|
|
|
}
|
|
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Send Orders (End)
|
|
Comment(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)));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Last Deal |
|
|
//+------------------------------------------------------------------+
|
|
stcDeal getLastDeal(const string strSymbol)
|
|
{
|
|
stcDeal dealLast;
|
|
ZeroMemory( dealLast );
|
|
ulong uTicket;
|
|
HistorySelect(0,TimeCurrent());
|
|
for(int i=0;i<(HistoryDealsTotal());i++)
|
|
{
|
|
uTicket=HistoryDealGetTicket(i);
|
|
if(HistoryDealGetString(uTicket,DEAL_SYMBOL)==strSymbol)
|
|
{
|
|
dealLast.enType=(ENUM_DEAL_TYPE)HistoryDealGetInteger(uTicket,DEAL_TYPE);
|
|
dealLast.strSymbol=HistoryDealGetString(uTicket,DEAL_SYMBOL);
|
|
dealLast.dbVolume=HistoryDealGetDouble(uTicket,DEAL_VOLUME);
|
|
dealLast.dbPrice=HistoryDealGetDouble(uTicket,DEAL_PRICE);
|
|
}
|
|
}
|
|
return( dealLast );
|
|
}
|
|
//+------------------------------------------------------------------+
|