How to calculate take profit from currency

 

I want to set take profit in currency for several orders (in same direction) in the settings.

Please help me to correctly calculate the price of take profit.

I think something like this (but most likely it is not correct):

struct STRUCT_SERIE
  {
   STRUCT_MARKET_ORDER orders[];
   double breakeven;
   double volTotal;
   double takeProfit;
   int    ordersNumb;
   bool   isActual;
  };

input double inpTakeProfitInCurrency = 100.0;

STRUCT_SERIE buy;
STRUCT_SERIE sell;

void OnStart()
  {
   updateSeries();
   double pointValue = _Point * MarketInfo(_Symbol, MODE_TICKVALUE) / MarketInfo(_Symbol, MODE_TICKSIZE);
   double takeProfitInPoints = inpTakeProfitInCurrency / (buy.volTotal * pointValue) * _Point;
   buy.takeProfit = NormalizeDouble(buy.breakeven + takeProfitInPoints, _Digits);
  }

Full code:

#property strict
const int ARR_RES_SIZE_ORDERS = 20;
struct STRUCT_MARKET_ORDER
  {
   double   stopLoss;
   double   takeProfit;
   double   price;
   int      type;
   int      ticket;
   double   volume;
   datetime time;
   STRUCT_MARKET_ORDER(){stopLoss = -1; takeProfit = -1; price = -1; type = -1; ticket = -1; volume = -1; time = 0;}
  };
struct STRUCT_SERIE
  {
   STRUCT_MARKET_ORDER orders[];
   double breakeven;
   double volTotal;
   double takeProfit;
   int    ordersNumb;
   bool   isActual;
  };

input double inpTakeProfitInCurrency = 100.0;

STRUCT_SERIE buy;
STRUCT_SERIE sell;

void OnStart()
  {
   updateSeries();
   double pointValue = _Point * MarketInfo(_Symbol, MODE_TICKVALUE) / MarketInfo(_Symbol, MODE_TICKSIZE);
   double takeProfitInPoints = inpTakeProfitInCurrency / (buy.volTotal * pointValue) * _Point;
   buy.takeProfit = NormalizeDouble(buy.breakeven + takeProfitInPoints, _Digits);
  }

void updateSeries()
  {
   buy.isActual = false;
   sell.isActual = false;
   buy.ordersNumb = 0;
   sell.ordersNumb = 0;
   if(!arrayResize(buy.orders, 0, __LINE__) || !arrayResize(sell.orders, 0, __LINE__))
      return;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!orderSelect(i, SELECT_BY_POS, MODE_TRADES, __LINE__))
         return;
      if(OrderSymbol() != _Symbol)
         continue;
      if(OrderType() == 0)
        {
         if(!arrayAdd(buy.orders, __LINE__))
            return;
         buy.ordersNumb++;
        }
      else if(OrderType() == 1)
        {
         if(!arrayAdd(sell.orders, __LINE__))
            return;
         sell.ordersNumb++;
        }
     }
   updateSeries_BeAndVolTotal(buy);
   updateSeries_BeAndVolTotal(sell);
   buy.isActual = true;
   sell.isActual = true;
  }

void updateSeries_BeAndVolTotal(STRUCT_SERIE &serie)
  {
   serie.volTotal = 0;
   if(serie.ordersNumb < 1)
      return;
   double volTotal = 0;
   double avgPrc = 0;
   for(int i = serie.ordersNumb - 1; i >= 0; i--)
     {
      serie.volTotal += serie.orders[i].volume;
      avgPrc += serie.orders[i].price * serie.orders[i].volume;
     }
   serie.breakeven = NormalizeDouble(avgPrc / volTotal, _Digits);
  }

bool arrayAdd(STRUCT_MARKET_ORDER &array[], int line)
  {
   int index;
   if(!arrayIncrease(array, index, line))
      return(false);
   structMarketOrderFillFromSeletcted(array[index]);
   return(true);
  }

void structMarketOrderFillFromSeletcted(STRUCT_MARKET_ORDER &var)
  {
   var.stopLoss    = NormalizeDouble(OrderStopLoss(), _Digits);
   var.takeProfit  = NormalizeDouble(OrderTakeProfit(), _Digits);
   var.price       = NormalizeDouble(OrderOpenPrice(), _Digits);
   var.type        = OrderType();
   var.ticket      = OrderTicket();
   var.volume      = OrderLots();
   var.time        = OrderOpenTime();
  }

bool arrayIncrease(STRUCT_MARKET_ORDER &array[], int &newLastIndex, int line)
  {
   int currentSize = ArraySize(array),
       newSize = currentSize + 1;
   newLastIndex = currentSize;
   return(arrayResize(array, newSize, line));
  }

bool arrayResize(STRUCT_MARKET_ORDER &array[], int newSize, int line)
  {
   ResetLastError();
   int returned = ArrayResize(array, newSize, ARR_RES_SIZE_ORDERS);
   int error    = GetLastError();
   if(returned == newSize && error == ERR_NO_ERROR)
      return(true);
   PrintFormat("ArrayResize error. New size %i, error %i, result %i, line %i.", newSize, error, returned, line);
   return(false);
  }

bool orderSelect(int index, int select, int pool, int line)
  {
   ResetLastError();
   if(OrderSelect(index, select, pool))
      return(true);
   if(select == SELECT_BY_TICKET)
      PrintFormat("Failed to select order by ticket %i. Error %i, line %i.", index, GetLastError(), __LINE__);
   else
     {
      if(pool == MODE_TRADES)
         PrintFormat("Failed to select an order among open and pending orders. Order index %i, number of orders %i, error %i, line %i.",
                     index, OrdersTotal(), GetLastError(), __LINE__);
      else PrintFormat("Failed to select an order among closed and deleted orders. Order index %i, number of orders %i, error %i, line %i.",
                       index, OrdersHistoryTotal(), GetLastError(), __LINE__);
     }
   return(false);
  }
Extract profit down to the last pip
Extract profit down to the last pip
  • www.mql5.com
The article describes an attempt to combine theory with practice in the algorithmic trading field. Most of discussions concerning the creation of Trading Systems is connected with the use of historic bars and various indicators applied thereon. This is the most well covered field and thus we will not consider it. Bars represent a very artificial entity; therefore we will work with something closer to proto-data, namely the price ticks.
 

I don't believe that no one knows how to do it.

Poorly readable code? Or maybe I didn't explain clearly?

I'm trying to calculate how many pips the price has to go from the breakeven price (several orders in the same direction) to get the specified profit in currency.

It's just that I don't understand how to use MODE_TICKVALUE and MODE_TICKSIZE correctly.

 

Example: several buy orders are open. I want to close them when their total profit reaches $100.

I think using OrderProfit() and OrderClose() is not efficient. It would be more correct to set take profits of orders in the place where their total profit will be $100.

This is what I am doing: trying to calculate the price at which take profits should be located

 

These are all the same equation written in different ways ...

[Volume]      = [Money Value] * [Tick Size] / ( [Tick Value] * [Stop Size] )
[Stop Size]   = [Money Value] * [Tick Size] / ( [Tick Value] * [Volume]    )
[Money Value] = [Volume]      * [Stop Size] * [Tick Value]   / [Tick Size]

[Volume] in lots
[Stop Size] in quote price change
[Money Value] in account currency
 
Fernando Carreiro #:

These are all the same equation written in different ways ...

Thank you for your answer

 

I don't understand why the value from the tooltip changes by itself.


 
Fernando Carreiro #:

These are all the same equation written in different ways ...

 Your method seems to give the same result, but requires less computation. I will use it, thanks.

#property strict

input double inpTakeProfitInCurrency = 100.0;

void OnStart()
  {
   if(!OrderSelect(0, SELECT_BY_POS))
      return;
   double first  = firstMethod(inpTakeProfitInCurrency, OrderOpenPrice(), OrderLots());
   double second = secondMethod(inpTakeProfitInCurrency, OrderOpenPrice(), OrderLots());
   Alert(StringFormat("Profit %.2f: first method %s, second method %s, results match %i",
                      inpTakeProfitInCurrency, prcToStr(first), prcToStr(second), first == second));
  }

double firstMethod(double money, double avgPrice, double volume)
  {
   double pointValue = _Point * MarketInfo(_Symbol, MODE_TICKVALUE) / MarketInfo(_Symbol, MODE_TICKSIZE);
   double takeProfitInPoints = money / (volume * pointValue) * _Point;
   return(avgPrice + takeProfitInPoints);
  }

double secondMethod(double money, double avgPrice, double volume)
  {
   return(avgPrice + money * MarketInfo(_Symbol, MODE_TICKSIZE) / (MarketInfo(_Symbol, MODE_TICKVALUE) * volume));
  }

string prcToStr(double price)
  {
   return(DoubleToString(price, _Digits));
  }


 
Vladislav Boyko # Your method seems to give the same result, but requires less computation. I will use it, thanks.
You are welcome.
 
Vladislav Boyko #:

 Your method seems to give the same result, but requires less computation. I will use it, thanks.


I will steal/copy most of the code, too! Thanks.

Reason: