//+------------------------------------------------------------------+ //| 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;i0) 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;j0) 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;i0)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;i0)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(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;p0) 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))); } //+------------------------------------------------------------------+