Position Sizing / Risk Management Indi

 

Hi Folks,

I've been using a position sizing indi in MT4 which a coder created, it works great (risk:reward, lot sizing etc.) but it uses the MT4 account balance as the default.

I use MT4 as my charting package but another broker for execution. I'm trying to modify this indicator to have a manual input of "Trading Capital" and use that in the lot/position sizing calculation, as opposed to using the Account Balance shown in Mt4.

Any help would be greatly appreciated,

Andrew

 
Just change account balance to something like accountbalanceused. You don't need people to help you. You can figure it out yourself since it is easy to change. Way easy actually.
 

Hi Deysmacro,

I'm new to MT4 coding, I've modified a couple of indis but only the basics. I wouldn't have posted in the forum if I could have figured it out by myself?

For the manual input of Account Capital I'm not sure where that entry goes, or what parts of the current indi to remove as they'll no longer be necessary?

 
//+------------------------------------------------------------------+
//|                                       PositionSizeCalculator.mq4 |
//|                             Copyright © 2012-2013, Andriy Moraru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2012-2013, Andriy Moraru"
#property link      "http://www.earnforex.com"

/*
   Calculates position size based on account balance/equity,
   currency, currency pair, given entry level, stop-loss level
   and risk tolerance (set either in percentage points or in base currency).
*/

#property indicator_chart_window

extern double EntryLevel = 0;
extern double StopLossLevel = 0;
extern double TakeProfitLevel = 0; // Optional
extern double Risk = 1; // Risk tolerance in percentage points
extern double MoneyRisk = 0; // Risk tolerance in base currency
extern bool UseMoneyInsteadOfPercentage = false;
extern bool UseEquityInsteadOfBalance = true;
extern double InsertBalanceHere = 1;
extern bool DeleteLines = false; // If true, will delete lines on deinitialization. Otherwise will leave lines, so levels can be restored.
extern bool UseAskBidForEntry = false; // If true, Entry level will be updated to current Ask/Bid price automatically.

extern color font_color = LightBlue;
extern color ps_font_color = Red;
extern int font_size = 12;
extern string font_face = "Courier";
extern int corner = 0; //0 - for top-left corner, 1 - top-right, 2 - bottom-left, 3 - bottom-right
extern int distance_x = 10;
extern int distance_y = 15;
extern color entry_line_color = Blue;
extern color stoploss_line_color = Lime;
extern color takeprofit_line_color = Yellow;

string SizeText;
double Size, RiskMoney;
double PositionSize;
double StopLoss;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   if (ObjectFind("EntryLine") > -1) EntryLevel = ObjectGet("EntryLine", OBJPROP_PRICE1);
   if (ObjectFind("StopLossLine") > -1) StopLossLevel = ObjectGet("StopLossLine", OBJPROP_PRICE1);
   if (ObjectFind("TakeProfitLine") > -1) TakeProfitLevel = ObjectGet("TakeProfitLine", OBJPROP_PRICE1);
   
   if ((EntryLevel == 0) && (StopLossLevel == 0))
   {
      Print(Symbol() + ": Entry and Stop-Loss levels not given. Using local values.");
      EntryLevel = High[0];
      StopLossLevel = Low[0];
      if (EntryLevel == StopLossLevel) StopLossLevel -= Point;
   }
   if (EntryLevel - StopLossLevel == 0)
   {
      Alert("Entry and Stop-Loss levels should be different and non-zero.");
      return(-1);
   }

   if (UseAskBidForEntry)
   {
      RefreshRates();
      if ((Ask > 0) && (Bid > 0))
      {
         // Long entry
         if (StopLossLevel < Bid) EntryLevel = Ask;
         // Short entry
         else if (StopLossLevel > Ask) EntryLevel = Bid;
      }
   }

   ObjectCreate("EntryLevel", OBJ_LABEL, 0, 0, 0);
   ObjectSet("EntryLevel", OBJPROP_CORNER, corner);
   ObjectSet("EntryLevel", OBJPROP_XDISTANCE, distance_x);
   ObjectSet("EntryLevel", OBJPROP_YDISTANCE, distance_y);
   ObjectSetText("EntryLevel", "Entry Lvl:    " + DoubleToStr(EntryLevel, Digits), font_size, font_face, font_color);

   if (ObjectFind("EntryLine") == -1) 
   {
      ObjectCreate("EntryLine", OBJ_HLINE, 0, Time[0], EntryLevel);
      ObjectSet("EntryLine", OBJPROP_STYLE, STYLE_SOLID);
      ObjectSet("EntryLine", OBJPROP_COLOR, entry_line_color);
      ObjectSet("EntryLine", OBJPROP_WIDTH, 1);
   }

   ObjectCreate("StopLoss", OBJ_LABEL, 0, 0, 0);
   ObjectSet("StopLoss", OBJPROP_CORNER, corner);
   ObjectSet("StopLoss", OBJPROP_XDISTANCE, distance_x);
   ObjectSet("StopLoss", OBJPROP_YDISTANCE, distance_y + 15);
   ObjectSetText("StopLoss", "Stop-Loss:    " + DoubleToStr(StopLossLevel, Digits), font_size, font_face, font_color);
      
   if (ObjectFind("StopLossLine") == -1)
   {
      ObjectCreate("StopLossLine", OBJ_HLINE, 0, Time[0], StopLossLevel);
      ObjectSet("StopLossLine", OBJPROP_STYLE, STYLE_SOLID);
      ObjectSet("StopLossLine", OBJPROP_COLOR, stoploss_line_color);
      ObjectSet("StopLossLine", OBJPROP_WIDTH, 1);
   }
   StopLoss = MathAbs(EntryLevel - StopLossLevel);
   
   if (!UseMoneyInsteadOfPercentage)
   {
      ObjectCreate("Risk", OBJ_LABEL, 0, 0, 0);
      ObjectSet("Risk", OBJPROP_CORNER, corner);
      ObjectSet("Risk", OBJPROP_XDISTANCE, distance_x);
      ObjectSet("Risk", OBJPROP_YDISTANCE, distance_y + 30);
      ObjectSetText("Risk", "Risk:         " + DoubleToStr(Risk, 2) + "%", font_size, font_face, font_color);
   }
   
   if (UseEquityInsteadOfBalance)
   {
      SizeText = "Equity";
      Size = InsertBalanceHere;
   }
   else
   {
      SizeText = "Balance";
      Size = AccountBalance();
   }
   ObjectCreate("AccountSize", OBJ_LABEL, 0, 0, 0);
   ObjectSet("AccountSize", OBJPROP_CORNER, corner);
   ObjectSet("AccountSize", OBJPROP_XDISTANCE, distance_x);
   ObjectSet("AccountSize", OBJPROP_YDISTANCE, distance_y + 45);
   ObjectSetText("AccountSize", "Acc. " + SizeText + ": " + DoubleToStr(Size, 2), font_size, font_face, font_color);
   
   ObjectCreate("RiskMoney", OBJ_LABEL, 0, 0, 0);
   ObjectSet("RiskMoney", OBJPROP_CORNER, corner);
   ObjectSet("RiskMoney", OBJPROP_XDISTANCE, distance_x);
   ObjectSet("RiskMoney", OBJPROP_YDISTANCE, distance_y + 60);

   ObjectCreate("PositionSize", OBJ_LABEL, 0, 0, 0);
   ObjectSet("PositionSize", OBJPROP_CORNER, corner);
   ObjectSet("PositionSize", OBJPROP_XDISTANCE, distance_x);
   ObjectSet("PositionSize", OBJPROP_YDISTANCE, distance_y + 75);

   if (TakeProfitLevel > 0) // Show TP line and RR ratio only if TakeProfitLevel input parameter is set by user or found via chart object.
   {
      ObjectCreate("TakeProfit", OBJ_LABEL, 0, 0, 0);
      ObjectSet("TakeProfit", OBJPROP_CORNER, corner);
      ObjectSet("TakeProfit", OBJPROP_XDISTANCE, distance_x);
      ObjectSet("TakeProfit", OBJPROP_YDISTANCE, distance_y + 90);
      ObjectSetText("TakeProfit", "Take-Profit:  " + DoubleToStr(TakeProfitLevel, Digits), font_size, font_face, font_color);

      if (ObjectFind("TakeProfitLine") == -1) 
      {
         ObjectCreate("TakeProfitLine", OBJ_HLINE, 0, Time[0], TakeProfitLevel);
         ObjectSet("TakeProfitLine", OBJPROP_STYLE, STYLE_SOLID);
         ObjectSet("TakeProfitLine", OBJPROP_COLOR, takeprofit_line_color);
         ObjectSet("TakeProfitLine", OBJPROP_WIDTH, 1);
      }
   
      ObjectCreate("RR", OBJ_LABEL, 0, 0, 0);
      ObjectSet("RR", OBJPROP_CORNER, corner);
      ObjectSet("RR", OBJPROP_XDISTANCE, distance_x);
      ObjectSet("RR", OBJPROP_YDISTANCE, distance_y + 105);
      ObjectSetText("RR", "Reward/Risk:  " + DoubleToStr(MathAbs((TakeProfitLevel - EntryLevel) / (EntryLevel - TakeProfitLevel)), 1), font_size, font_face, takeprofit_line_color);
   }
   
   CalculateRiskAndPositionSize();

   return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObjectDelete("EntryLevel");
   if (DeleteLines) ObjectDelete("EntryLine");
   ObjectDelete("StopLoss");
   if (DeleteLines) ObjectDelete("StopLossLine");
   if (!UseMoneyInsteadOfPercentage) ObjectDelete("Risk"); // Otherwise wasn't created.
   ObjectDelete("AccountSize");
   ObjectDelete("RiskMoney");
   ObjectDelete("PositionSize");
   if (TakeProfitLevel > 0)
   {
      ObjectDelete("TakeProfit");
      if (DeleteLines) ObjectDelete("TakeProfitLine");
      ObjectDelete("RR");
   }
   return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   double tEntryLevel, tStopLossLevel, tTakeProfitLevel;
   // Update Entry to Ask/Bid if needed.
   if (UseAskBidForEntry)
   {
      RefreshRates();
      if ((Ask > 0) && (Bid > 0))
      {
         tStopLossLevel = ObjectGet("StopLossLine", OBJPROP_PRICE1);
         // Long entry
         if (tStopLossLevel < Bid) tEntryLevel = Ask;
         // Short entry
         else if (tStopLossLevel > Ask) tEntryLevel = Bid;
         ObjectSet("EntryLine", OBJPROP_PRICE1, tEntryLevel);
      }
   }
   
   if (EntryLevel - StopLossLevel == 0) return(0);

   // If could not find account currency, probably not connected.
   if (AccountCurrency() == "") return(0);

   tEntryLevel = ObjectGet("EntryLine", OBJPROP_PRICE1);
   tStopLossLevel = ObjectGet("StopLossLine", OBJPROP_PRICE1);
   tTakeProfitLevel = ObjectGet("TakeProfitLine", OBJPROP_PRICE1);
   ObjectSetText("EntryLevel", "Entry Lvl:    " + DoubleToStr(tEntryLevel, Digits), font_size, font_face, font_color);
   ObjectSetText("StopLoss", "Stop-Loss:    " + DoubleToStr(tStopLossLevel, Digits), font_size, font_face, font_color);
   if (tTakeProfitLevel > 0) ObjectSetText("TakeProfit", "Take-Profit:  " + DoubleToStr(tTakeProfitLevel, Digits), font_size, font_face, font_color);

   StopLoss = MathAbs(tEntryLevel - tStopLossLevel);

   if (tTakeProfitLevel > 0)
   {
      string RR;
      // Have valid take-profit level that is above entry for SL below entry, or below entry for SL above entry.
      if (((tTakeProfitLevel > tEntryLevel) && (tEntryLevel > tStopLossLevel)) || ((tTakeProfitLevel < tEntryLevel) && (tEntryLevel < tStopLossLevel)))
         RR = DoubleToStr(MathAbs((tTakeProfitLevel - tEntryLevel) / StopLoss), 1);
      else RR = "Invalid TP.";
      ObjectSetText("RR", "Reward/Risk:  " + RR, font_size, font_face, takeprofit_line_color);
   }
   
   if (UseEquityInsteadOfBalance && InsertBalanceHere>0) Size = InsertBalanceHere;
   else Size = AccountBalance();
   ObjectSetText("AccountSize", "Acc. " + SizeText + ": " + DoubleToStr(Size, 2), font_size, font_face, font_color);

   CalculateRiskAndPositionSize();

   return(0);
}

//+------------------------------------------------------------------+
//| Calculates risk size and position size. Sets object values.      |
//+------------------------------------------------------------------+
void CalculateRiskAndPositionSize()
{
   if (!UseMoneyInsteadOfPercentage) RiskMoney = Size * Risk / 100;
   else RiskMoney = MoneyRisk;
   ObjectSetText("RiskMoney", "Risk, money:  " + DoubleToStr(RiskMoney, 2), font_size, font_face, font_color);

   double UnitCost = MarketInfo(Symbol(), MODE_TICKVALUE);
   double TickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
   if ((StopLoss != 0) && (UnitCost != 0) && (TickSize != 0)) PositionSize = RiskMoney / (StopLoss * UnitCost / TickSize);
   
   ObjectSetText("PositionSize", "Pos. Size:    " + DoubleToStr(PositionSize, 2), font_size + 1, font_face, ps_font_color);

}
//+------------------------------------------------------------------+


There you go. See if you can spot the differences. XD

Took me < 1 minute to complete. XD

 

Hi Deysmacro,

Thanks for your help, but it hasn't solved the problem unfortunately. The Position size calculation uses the account equity amount also. Of course it took you less than a minute, you already speak this (mq4) language and can read it.

Still learning over this way, I'm ok with Excel and some visual basic, but it's just knowing what call ups etc.. to use.

Would I substitute "riskmoney" with InsertBalancehere?

 
If you read/study it very carefully, it would not use account equity, but your inserted balance. The inserted balance must be above zero though. It is double, so 1.00 not 1.
 
The main (ha, main, like there's only *one*) confusing thing I found, was that it called up "RiskMoney" out of no where without defining it first?
 

Ah yep, I'm with you now. Seems to be working quite happily :)

One more Q (unrelated to coding!) is that the positon size calc almost seems to be wrong? For something as simple as a 10 pip SL, $10,000 equity etc the lot size isn't coming out with the right calc? Almost like's it's got some leeway in there for slippage or something? I've gone over the maths/code as best I can but couldn't find anything out of the ordinary.

 

Yes. You have to make your own math and see if the calculations tally with it.

I do my own math, so I know where it has gone wrong if it is not working like it should.

Basically, there is a lot of homework to be done by you.

 
Thank you for your help with this, much appreciated.
Reason: