Setting the Total Profit
Many traders are well aware of the Martingale tactic - increasing the volume of the transaction after each loss. This tactics is guaranteed to win, but as always has one "but". To fully guarantee a profit it is necessary to have an infinitely large amount of money. Therein lies the main contradiction. Why try to increase the capital, if its size is already infinite?
Nevertheless, on a local scale, the application Martingale tactics has the right to life. For example, such a modification of the tactic as adding to a losing position. In this case the emphasis is made on the improvement (decrease for long trades and increase for short trades) of the average opening price of an aggregate trade. As a consequence, the price no longer needs to return to the profit level of the first position to get the planned total profit. The corresponding new profit level can be located much closer to the current price, which increases the probability of reaching it.
The main trader's headache in applying such trading tactics is to determine the average opening price of several unidirectional trades, as well as the total level of profit, which must correspond to the value of the profit, which was planned to get at the opening of the first position.
An assistant to the trader in this case can be an ordinary script that will calculate the aggregate level of profit as if the profit was achieved by only one trade.
The algorithm of the script follows from its main functions - start:
int start()
{
// - 1 - =========== Get information about trading conditions ===========
Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // minimum tick
TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); // tick value in the deposit currency
Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // current spread
StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // current stop level
// - 1 - ================ End of Block ========================
// - 2 - ================= Check the correctness of TakeProfit ============
if (TakeProfit <= (StopLevel-Spread)/Point)
{
Alert("TakeProfit must be greater than ", (StopLevel-Spread)/Point, " points;)
return(0);
}
if (Lots < MarketInfo(Symbol(), MODE_MINLOT))
{
Alert("The specified volume value is too low!");
return(0);
}
// - 2 - ==================== End of Block ====================
// - 3 - ================ Continuous monitoring of positions ==============
while (!IsStopped())
{
GetAveragePrices(); // Calculate average opening price and total profit
if (BuyProfit > 0 || SellProfit > 0) // if there are positions on the current instrument
{
TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); // Tick price in the deposit currency
Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // current spread
StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // stop level
SetCommonProfit(); // set profit levels to the desired level
}
}
// - 3 - ============= End of Block ===========================
return(0);
}
First Block simply collects the necessary information - the value of the spread and the minimum level of stops. Another value that will be needed when the script works is the value of one minimum price change in the deposit currency. In other words, it is the cost of one tick for one full lot.
Second block is responsible for checking if the user correctly enters the two input parameters of the script - TakeProfit and Lots. The first parameter sets the number of points of the planned profit, and the second parameter sets the volume of the trade, by which this profit is planned to be obtained.
Third block contains an "infinite loop" that can still be terminated by the user when disconnecting of the script from the chart. The aggregate level of profit for long trades (BuyProfit) and for short ones (SellProfit) is calculated in the body of the cycle. This is done by the GetAveragePrices function. The next step is to set the calculated profit level for all found positions, this is done by the SetCommonProfit function.
GetAveragePrices function works like this:
void GetAveragePrices()
{
// - 1 - ======= Find all trades for the current instrument ===========
BuyProfit = 0; SellProfit = 0;
double BuyAveragePrice = 0, SellAveragePrice = 0;
double BuyLots = 0, SellLots = 0;
for (int i = 0; i < OrdersTotal(); i++)
if (OrderSelect(i, SELECT_BY_POS))
if (OrderType() < 2) // only positions are taken into account
if (OrderSymbol() == Symbol()) // and only the current instrument
if (OrderType() == OP_BUY)
{
BuyAveragePrice += OrderOpenPrice()*OrderLots(); // Average opening price
BuyLots += OrderLots(); // and total volume for long positions
}
else
{
SellAveragePrice += OrderOpenPrice()*OrderLots(); // Average opening price
SellLots += OrderLots(); // and total volume for short positions
}
// - 1 - ============= End of Block ===========================
// - 2 - ====== Calculation of the total closing price of trades, taking into account the target profit ====
// how much profit is required in the deposit currency
double TargetProfit = TickValue*Lots*TakeProfit;
if (BuyLots != 0)
BuyProfit = BuyAveragePrice/BuyLots + Tick*(TargetProfit/(TickValue*BuyLots));
if (SellLots != 0)
SellProfit = SellAveragePrice/SellLots - Tick*(TargetProfit/(TickValue*SellLots));
// - 2 - ================ End of Block ========================
}
Next the level of profit is calculated for long trades BuyProfit. For this purpose we add the expression Tick*(TargetProfit/(TickValue*BuyLots)) to the average opening price (ratio of BuyAveragePrice to BuyLots), which we dissect in parts. So, TickValue*BuyLots is the change of equity (Equity) in the deposit currency with every tick. Therefore, if we divide the planned profit (TargetProfit) by it, we obtain the number of points to be added to the average opening price.
The level of profit for short SellProfit positions is calculated in the same way.
The last one under consideration SetCommonProfit function:
void SetCommonProfit()
{
// - 1 - ========= Finding positions by current instrument ===============
for (int i = 0; i < OrdersTotal(); i++)
if (OrderSelect(i, SELECT_BY_POS))
if (OrderType() < 2) // only positions are taken into account
if (OrderSymbol() == Symbol()) // and only the current instrument
// - 1 - ==================== End of block ========================
{
double TP = 0; // If 0, no change is necessary
// - 2 - ============== Check long positions =======================
if (OrderType() == OP_BUY && BuyProfit > 0) // If the profit level is calculated,
if (MathAbs(OrderTakeProfit() - BuyProfit) >= Tick && //different from current
BuyProfit - Bid > StopLevel) // and distance to change enough
TP = NP(BuyProfit);
// - 2 - =============== End of Block =============================
// - 3 - ============ Check short positions =========================
if (OrderType() == OP_SELL && SellProfit > 0)// If the profit level is calculated,
if (MathAbs(OrderTakeProfit() - SellProfit) >= Tick&& //different from current
Ask - SellProfit > StopLevel) // and distance to change enough
TP = NP(SellProfit);
// - 3 - ===================== End of Block =======================
// - 4 - ============== Changing the TakeProfit level of the position =================
if (TP > 0) // change is required if the new level is not zero
if (WaitForTradeContext())
if (!OrderModify(OrderTicket(), 0, OrderStopLoss(), TP, 0))
return;
// - 4 - ===================== End of Block =======================
}
}
First Block simply finds deals on the current instrument.
Second block checks compliance of the profit level of the found long trade with the calculated total BuyProfit level. If the current profit level is not equal to the calculated one and the current Bid value is far enough from BuyProfit, the Take Profit level of the trade will be changed.
Third block is a copy of the second one, the only difference being that it works with short positions.
The fourth block is directly involved in the modification of the profit level, which occurs if the value of the TP variable is not equal to zero.
The script can be used with one or more currency pairs simultaneously. Its task is to monitor the profit level of all open positions. Therefore, when opening a new trade, profit level can simply not be specified.
In the script settings it is sufficient to specify the number of points to be gained (TakeProfit) and volume of the first transaction (Lots)on the basis of which the cumulative profit will be calculated. Note that the resulting profit will be slightly different from the planned one, but for the better. This happens because it is impossible to specify a fractional number of points when setting goals for each transaction.
After launching of the script The trader must manually open trades, specifying only the level of stop order. With the opening of each new trade, the profit level of each position will be automatically changed by the script.
The full source code of the script can be found here.