Portfolio/Portfolio.mq5
super.admin 2dcba7a4a7 convert
2025-05-30 16:16:46 +02:00

284 lines
No EOL
28 KiB
MQL5

//+------------------------------------------------------------------+
//| Portfolio.mq5 |
//| Copyright 2022, Allan |
//| 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 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;
---------------------------------*/
};
//+------------------------------------------------------------------+
//| Entradas |
//+------------------------------------------------------------------+
sinput CalcMode inpCalcMode=Median;//Modo de Cálculo:
sinput ulong inpRatesQuantidade=52;//Quantidade de dias:
sinput double inpFinancialTicket=500.0;//Ficha financeira (brl):
sinput double inpBalanceCorrection=0.0;//Correção do Patrimônio (brl):
//+------------------------------------------------------------------+
//| Variaveis Globais |
//+------------------------------------------------------------------+
double gdbBalance=inpBalanceCorrection;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
EventSetTimer(1);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//gdbBalance=AccountInfoDouble(ACCOUNT_BALANCE)+inpBalanceCorrection;
//double dbCorrectionBalance=AccountInfoDouble(ACCOUNT_BALANCE)-inpBalanceCorrection;
//gdbBalance=AccountInfoDouble(ACCOUNT_BALANCE)+dbCorrectionBalance;
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;
*/
string 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[];
double dbPortfolioReturn=0.0;
double dbPortfolioRisk=0.0;
ulPositionTicket=0;
for(int i=0;i<PositionsTotal();i++)
{
ulPositionTicket=PositionGetTicket(i);
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;
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);
strComment+="\n";
strComment+=StringFormat("Balance: %.2f, r=%.2f%%, s=%.2f%%, ld=%.2f%%\n%7s: r=%.2f%%, s=%.2f%%, cv=%.5f, vol=%.0f, w=%.2f%%\n",
gdbBalance,
100*dbPortfolioReturn,
100*MathSqrt(dbPortfolioRisk),
100*dbExposure/gdbBalance,
_Symbol,
100*dbSymbol_r,
100*MathSqrt(dbSymbol_s),
MathSqrt(dbSymbol_s)/dbSymbol_r,
MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode)),
100*(MathRound(inpFinancialTicket/SymbolPrice(_Symbol,inpCalcMode))*SymbolPrice(_Symbol,inpCalcMode))/gdbBalance
);
strComment+="\n";
stcDeal lastDeal;
ulong ulHistoryDealTicket=0;
HistorySelect(0,TimeCurrent());
for(int i=0;i<SymbolsTotal(true);i++)
{
if(SymbolInfoDouble(SymbolName(i,true),SYMBOL_OPTION_STRIKE)==0.0)
{
ZeroMemory(lastDeal);
for(int h=0;h<HistoryDealsTotal();h++)
{
ulHistoryDealTicket=HistoryDealGetTicket(h);
if(HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL)==SymbolName(i,true))
if(HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TIME)>(long)lastDeal.dtTime)
{
lastDeal.strSymbol=HistoryDealGetString(ulHistoryDealTicket,DEAL_SYMBOL);
lastDeal.enType=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TYPE);
lastDeal.dtTime=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_TIME);
lastDeal.dbPrice=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_PRICE);
lastDeal.dbVolume=HistoryDealGetDouble(ulHistoryDealTicket,DEAL_VOLUME);
lastDeal.lPositionID=HistoryDealGetInteger(ulHistoryDealTicket,DEAL_POSITION_ID);
}
}
if(lastDeal.dbPrice>0.0)
{
stcDeal dealSimulation; ZeroMemory(dealSimulation);
dealSimulation.strSymbol=lastDeal.strSymbol;
dealSimulation.dbPrice=SymbolPrice(dealSimulation.strSymbol,inpCalcMode);
dealSimulation.dbVolume=MathRound(inpFinancialTicket/SymbolPrice(lastDeal.strSymbol,inpCalcMode));
if(lastDeal.enType==DEAL_TYPE_BUY)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)>lastDeal.dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_SELL;ObjectCreate(0,"Stocks_SimulationSell",OBJ_HLINE,0,0,lastDeal.dbPrice/(1-(lastDeal.dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_COLOR,clrFireBrick);}
if(lastDeal.enType==DEAL_TYPE_BUY)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)<=lastDeal.dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_BUY;}
if(lastDeal.enType==DEAL_TYPE_SELL)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)>lastDeal.dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_SELL;ObjectCreate(0,"Stocks_SimulationSell",OBJ_HLINE,0,0,lastDeal.dbPrice/(1-(lastDeal.dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationSell",OBJPROP_COLOR,clrFireBrick);}
if(lastDeal.enType==DEAL_TYPE_SELL)if(SymbolPrice(dealSimulation.strSymbol,inpCalcMode)<=lastDeal.dbPrice){dealSimulation.enType=(ENUM_DEAL_TYPE)DEAL_TYPE_BUY;ObjectCreate(0,"Stocks_SimulationBuy",OBJ_HLINE,0,0,lastDeal.dbPrice*(1-(lastDeal.dbPrice*dealSimulation.dbVolume)/gdbBalance));ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_STYLE,STYLE_DASHDOT);ObjectSetInteger(0,"Stocks_SimulationBuy",OBJPROP_COLOR,clrMidnightBlue);}
if(((dealSimulation.enType==DEAL_TYPE_BUY?(lastDeal.dbPrice-dealSimulation.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice)):(dealSimulation.dbPrice-lastDeal.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice))) )>((MathRound(inpFinancialTicket/SymbolPrice(lastDeal.strSymbol,inpCalcMode))*SymbolPrice(lastDeal.strSymbol,inpCalcMode))/gdbBalance) )
{
if(dealSimulation.enType==DEAL_TYPE_SELL)
{
double dbExposureVolume=0.0;
ulPositionTicket=0;
for(int p=0;p<PositionsTotal();p++)
{
ulPositionTicket=PositionGetTicket(p);
if(PositionGetSymbol(p)==lastDeal.strSymbol)
{
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)dbExposureVolume+=PositionGetDouble(POSITION_VOLUME);
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)dbExposureVolume-=PositionGetDouble(POSITION_VOLUME);
}
}
if(dbExposureVolume>0)
strComment+=StringFormat("%s %s %5.2f%%\n",
StringSubstr(EnumToString((ENUM_DEAL_TYPE)dealSimulation.enType),10,5),
dealSimulation.strSymbol,
100*((dealSimulation.enType==DEAL_TYPE_BUY?(lastDeal.dbPrice-dealSimulation.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice)):(dealSimulation.dbPrice-lastDeal.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice))))
);
}
else
{
strComment+=StringFormat("%s %s %5.2f%%\n",
StringSubstr(EnumToString((ENUM_DEAL_TYPE)dealSimulation.enType),10,5),
dealSimulation.strSymbol,
100*((dealSimulation.enType==DEAL_TYPE_BUY?(lastDeal.dbPrice-dealSimulation.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice)):(dealSimulation.dbPrice-lastDeal.dbPrice)/(2/(1/dealSimulation.dbPrice+1/lastDeal.dbPrice))))
);
}
}
}
}
}
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)));
}
//+------------------------------------------------------------------+