Culture of coding

Culture of coding

7 March 2016, 11:20
eevviill7
[Deleted]
0
438

Introduction

Hello dear readers.

In this article I will try to present their vision of cultural writing code. As one familiar programmer "code should be written so that the programmer who wrote the code was opened after 6 years and could razobratsya 20 minutes in it." In the above privacy if akuratno learning to write code that can vprintsype nobody except a programmer and do not see it in my life will be easier to cultivate a culture. 



1. Examples and explanations

1.1 enum

Deployed about  enum  can be found here  What is the enum?

Words programmer  enum  is manually creating a list of variables of type int. Mostly used to indicate a range of possible options in the external variables or to an external variable when choosing a drop-down list of options, not just fit the desired constant. It is necessary to take into account the fact that the  enum  should be used only in those cases when your list can not go beyond the range of theoretically possible value. For example, the months may be only 1 to 12. A MovingAverage display period can be from 1 to infinity. The numbering of the elements with the list of  enum starts at 0. 

 

Example 1.1.1. The minutes for the start of the EA.

enum minutes
{
M_0=0,M_15=15,M_30=30,M_45=45,M_60=60
};

extern minutes Start_m = 0;

So. Instead of the usual type of data after the extern, write the name list of  an enum .  Start_m =  1 is equivalent to the value of 1 is assigned by the element in the list. In this case M_15. If M_15 = 90, then  Start_m = 90 too.

Now let us compare the difference with screenshots using  enum  and without.

Figure 1.1.1. 

 

 Figure 1.1.2. 

 

Example 1.1.2. Using the true / false alternatives

So you can change the name of prevychnoe true / false to the fact, what you want.

enum bools
{
fal=0, //Не использовать
tru=1  //Использовать
};


extern bools work_time = 0;

 

 It appears so.

 Figure 1.1.3. 

 

 

There is also a built-in  an enum .

For example the method of Moving Average and timeframes.

extern  ENUM_MA_METHOD   ma_method = MODE_SMA ;
extern  ENUM_TIMEFRAMES MA_TF = PERIOD_D1 ;

 

 

1.2. data types for integers

As we know after the upgrade the terminal to the 600 build, and new data types. 

In the above privacy integer types. About them can be read here  Data Types .  

Proper use of the type of data helps save the amount of memory usage of home computers.

If code size is large, it can save more than appropriately.

 

Example 1.2.1. function sends a signal to open orders

int Sig_f()
{
//сигнал для бай
if(Close[1]>Open[1]) return(1);

//сигнал для сел
if(Close[1]<Open[1]) return(-1);


return(0);
}

 

As we can see the int function. It may return the value of 3 (0,1, -1).

It is only logical that the function had a char. 

char Sig_f()
{
//сигнал для бай
if(Close[1]>Open[1]) return(1);

//сигнал для сел
if(Close[1]<Open[1]) return(-1);


return(0);
}

 

 

 Example 1.2.2. step between orders

extern int step = 40 ;

As we understand the step between orders can not be negative.

It is logical to write the data type uint.

extern uint step = 40 ;

 

 

1.3. call indicator

There are situations when the EA is the main signal that will uchavstvuvat code in any, but there are switchable filters.

Example 1.3.1

char Sig_f()
{
double Stoch=iStochastic(Symbol(),0,Kperiod,Dperiod,slowing,method,price_field,0,1);

//buy
if(Close[1]>Open[1] && (!use_stoch_filter || Stoch<stoch_overSold)) return(1);
//sell
if(Close[1]<Open[1] && (!use_stoch_filter || Stoch>stoch_overBought)) return(-1);


return(0);
}

 

In this case, the filter acts we Stochastic indicator.

As we see it is called, regardless of whether we use it or not.

It is logical that if it was not used, and it is not called.

Example 1.3.2.

char Sig_f()
{
double Stoch=EMPTY_VALUE;
if(use_stoch_filter) Stoch=iStochastic(Symbol(),0,Kperiod,Dperiod,slowing,method,price_field,0,1);

//buy
if(Close[1]>Open[1] && (!use_stoch_filter || Stoch<stoch_overSold)) return(1);
//sell
if(Close[1]<Open[1] && (!use_stoch_filter || Stoch>stoch_overBought)) return(-1);


return(0);
}

 

 

There are situations when the user indicators are caused by external variables alerts, sending signals to the post office, drawing objects, just text external variables that do not mean anything.

When you call a counselor indicator, these functions are not necessary, and we will disable.   

Example 1.3.3. 

extern string ind1_name = "Indicator Fox";
extern int PeriodIndikator = 9;
extern double Factor = 2;
extern bool ind_alert = false;
extern bool ind_sound = false;
extern bool ind_email = false;


///////////////////////////////////
void OnTick()
{
double fox=iCustom(Symbol(),0,ind1_name,PeriodIndikator,Factor,ind_alert,ind_sound,ind_email,0,1);

}

 

 Advisor settings will looks like.

 Figure 1.3.1. 

 

But it is quite logical to setup the alert, sound and e-mail was not in the explanatory variables on the external display settings in the EA.

We have them in the off mode immediately write to the settings in the call display. 

Example 1.3.4.

extern string ind1_name = "Indicator Fox";
extern int PeriodIndikator = 9;
extern double Factor = 2;


///////////////////////////////////
void OnTick()
{
double fox=iCustom(Symbol(),0,ind1_name,PeriodIndikator,Factor,false,false,false,0,1);

}

 

 Now extra settings indicator external variables advisor will not.

 Figure 1.3.2. 

 

 

 

1.4. Use custom buffers (step)

 Let's see how to use the custom buffers pokulturnee write the code where we will have a lot of steps between the values ​​of orders depending on how many orders open. 

So. For example we need martingale with a maximum of 4 steps (up to 5 orders in the market).

After all the calculations we need to move. Do not bothered, the easiest way to write this.

Example 1.4.1.

extern uint step1=30;
extern uint step2=35;
extern uint step3=25;
extern uint step4=35;

///////////////////////////////////////////
int OnInit()
{  

return(INIT_SUCCEEDED);
}

////////////////////////////////////////////
int start()
{
...
uint step_to_chek=0;
if(OrdersTotal()==0) step_to_chek=step1; 
if(OrdersTotal()==1) step_to_chek=step2;
if(OrdersTotal()==2) step_to_chek=step3;
if(OrdersTotal()==3) step_to_chek=step4;
...
return(0);
}

 

 And if to use user buffer, it will much brevity.

 Example 1.4.2.

extern uint step1=30;
extern uint step2=35;
extern uint step3=25;
extern uint step4=35;

uint steps[4];

///////////////////////////////////////////
int OnInit()
{  
steps[0]=step1; steps[1]=step2; steps[2]=step3; steps[3]=step4;

return(INIT_SUCCEEDED);
}

////////////////////////////////////////////
int start()
{
...
uint step_to_chek=0;
if(OrdersTotal()>0) step_to_chek=steps[OrdersTotal()-1];
...
return(0);
}

 

 

 

1.5. Use custom functions or code in OnTick ()

Every programmer has its own style of writing code. This is certainly the right of everyone, but I stick to the position that everything should obschityvatsya in functions.

There is no point for example in the EA load OnTick code (). When everything in a pile of difficult razobratsya then if there is a mistake or need to change the algorithm advisor.

Then changing that one thing should be skurpulozno look after the rest of the code that does not follow the logic of got lost. 

Here, for example look like 3 steps if they are not in function.

Example 1.5.1. 

//////////////////////////////////////////////
void OnTick()
{
 double Free    =AccountFreeMargin();
 double One_Lot =MarketInfo(Symbol(),MODE_MARGINREQUIRED);
 double Step    =MarketInfo(Symbol(),MODE_LOTSTEP);
 double Loto     =MathFloor(Free*Risk/100/One_Lot/Step)*Step;
 
 double Min_Lot =MarketInfo(Symbol(),MODE_MINLOT);
 double Max_Lot =MarketInfo(Symbol(),MODE_MAXLOT);
 if(Loto<Min_Lot) Loto=Min_Lot;
 if(Loto>Max_Lot) Loto=Max_Lot;
 

  for (int i=OrdersTotal()-1; i>=0; i--) 
  {
  if(OrderSelect(i, SELECT_BY_POS)) 
  {
  if(OrderSymbol() == Symbol())
  { 
  if (OrderMagicNumber()==Magic)
  {
  while(IsTradeContextBusy()) Sleep(int(pause_if_busy*1000));
  RefreshRates();
  
      if (OrderType()==OP_BUY) 
      {
      if(OrderStopLoss()!=OrderOpenPrice()+NormalizeDouble(Bez_Ub_Size*point,Digits))
      {
      if (Bid>OrderOpenPrice()+Bez_Ub_Level*point && (OrderStopLoss()<OrderOpenPrice() || OrderStopLoss()==0)) 
      {
      if(OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+NormalizeDouble(Bez_Ub_Size*point,Digits),OrderTakeProfit(),0,clrNONE))
      continue;       
      }
      }
      }
      

      if (OrderType()==OP_SELL) 
      {
      if(OrderStopLoss()!=OrderOpenPrice()-NormalizeDouble(Bez_Ub_Size*point,Digits))
      {
      if (Ask<OrderOpenPrice()-Bez_Ub_Level*point && (OrderStopLoss()>OrderOpenPrice() || OrderStopLoss()==0)) 
      {
      if(OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-NormalizeDouble(Bez_Ub_Size*point,Digits),OrderTakeProfit(),0,clrNONE))
      continue;
      }
      }  
      }   
  }
  }
  }
  }


  for(int i=0; i<OrdersTotal(); i++) 
  { 
    if(OrderSelect(i, SELECT_BY_POS))
    {
    if(OrderSymbol() == Symbol())
    {        
    if(OrderMagicNumber()==Magic)
    {

    if(OrderType()==OP_BUY) 
      { 
      if(Bid>=NormalizeDouble(OrderOpenPrice()+TrailingStart*point+TrailingStop*point,Digits)) 
      { 
        if(NormalizeDouble(OrderStopLoss(),Digits)<NormalizeDouble(Bid-(TrailingStop+TrailingStep)*point,Digits))
        {
        if(NormalizeDouble(OrderStopLoss(),Digits)!=NormalizeDouble(Bid-TrailingStop*point,Digits))
        {
        while(IsTradeContextBusy()) Sleep(int(pause_if_busy*1000));
        RefreshRates();
          if(OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Bid-TrailingStop*point,Digits), OrderTakeProfit(), 0, clrNONE))
          continue;
        } 
        }
      }
      } 

    if(OrderType()==OP_SELL) 
      { 
      if(Ask<=NormalizeDouble(OrderOpenPrice()-TrailingStart*point-TrailingStop*point,Digits)) 
      { 
        if((NormalizeDouble(OrderStopLoss(),Digits)>NormalizeDouble(Ask+(TrailingStop+TrailingStep)*point,Digits)) || OrderStopLoss()==0) 
        {
        if(NormalizeDouble(OrderStopLoss(),Digits)!=NormalizeDouble(Ask+TrailingStop*point,Digits))
        {
        while(IsTradeContextBusy()) Sleep(int(pause_if_busy*1000));
        RefreshRates();
          if(OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Ask+TrailingStop*point,Digits), OrderTakeProfit(), 0, clrNONE))
          continue;
        }
        }
      }
      } 
    }
    }
    } 
  }
  

}//end on tick

 

It's hard to change something then, or find, is not it?

Now let's look at the code if the user-defined function.

Example 1.5.2. 

void OnTick()
{
double lot=GetLot();
Traling_Stop_f();
NoLoss_f();

}//enf on tick


//functions
//////////////////////////////////////////////////////////////////
double GetLot()
{
...
}

////////////////////////////////////////////////////////////////
void NoLoss_f()
{
...
}

///////////////////////////////////////////////////////////////////////////
void Traling_Stop_f()
{
...  
}

 

We OnTick () function calls placed only. It is very convenient.

We can easily change the order of function calls simply by changing the line in some places, set the conditions for the function call, edit, the function itself does not fear that the rest of the code logic can be broken.


 

1.6. Central bars in the indicator

As we know there is a standard way in which converted all the bars, and then only the current.

Example 1.6.1.

for(int i=Bars-IndicatorCounted()-1;i>=0;i--)
{
...
}

 

 And what to do if it is necessary initially to calculate not all the bars and then to count not just the current bar?

I propose a model.


Oh)))) 

Example 1.6.2.  

extern int Bars_To_Count = 400;
extern int Bars_To_Recount = 4;

int BarsCount;
bool count_chek;

//////////////////////////////////////////////////////////////////
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],const double &open[],const double &high[],
                const double &low[],const double &close[],const long &tick_volume[],const long &volume[],const int &spread[])
  {
   for(int i=BarsCount;i>=0;i--)
{
if(i>int(Bars-1)) i=Bars-1;
...
}


//recount chek
if(!count_chek)
{
count_chek=true;
BarsCount=Bars_To_Recount;
}

   return(rates_total);
  }

 

So. When attaching we calculate the right amount of bars, and then the right amount will be recalculated constantly.

 

 

1.7. creation and deletion of objects with an ID

The indicators depict the objects in the chart, and often there is a need advisors to create objects.

For example, we need to create two text objects.

Example 1.7.1. 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],const double &open[],const double &high[],
                const double &low[],const double &close[],const long &tick_volume[],const long &volume[],const int &spread[])
  {
string name="Leverage";
if(ObjectFind(name)==-1)
{
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_CORNER,0);
ObjectSetInteger(0,name, OBJPROP_XDISTANCE,20);
ObjectSetInteger(0,name, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(0,name, OBJPROP_COLOR, clrBlue);
ObjectSetString(0,name,OBJPROP_TEXT,"Leverage"+": "+string(AccountLeverage()));
}
name="AccFreeMarg";

if(ObjectFind(name)==-1)
{
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_CORNER,0);
ObjectSetInteger(0,name, OBJPROP_XDISTANCE,20);
ObjectSetInteger(0,name, OBJPROP_YDISTANCE, 45);
ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(0,name, OBJPROP_COLOR, clrGreen);
}
ObjectSetString(0,"AccFreeMarg",OBJPROP_TEXT,"AccountFreeMargin"+": "+string(AccountFreeMargin()));


 return(rates_total);
  }

 

And in  OnDeinit ()  should be written as follows.

Example 1.7.2. 

//////////////////////////////////////////////////
void OnDeinit(const int reason)
{
 if(ObjectFind("Leverage")!=-1)         ObjectDelete("Leverage");
 if(ObjectFind("AccFreeMarg")!=-1)  ObjectDelete("AccFreeMarg");
 }

 

It seems to be okay. And if we need to create 900 objects with different names?

At first. To create such a large number will have to use a function that will transmit the name of the object, color, location, etc. It vprintspe correctly.

Secondly. In  OnDeinit ()  will have to write in this way as in example 1.7.2. Total 900! lines.

But if you create objects with an ID, then you can vozpolzovatsya this design.

Example 1.7.3. 

string identif="mql5 статья";
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],const double &open[],const double &high[],
                const double &low[],const double &close[],const long &tick_volume[],const long &volume[],const int &spread[])
  {
string name="Leverage"+identif;
if(ObjectFind(name)==-1)
{
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_CORNER,0);
ObjectSetInteger(0,name, OBJPROP_XDISTANCE,20);
ObjectSetInteger(0,name, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(0,name, OBJPROP_COLOR, clrBlue);
ObjectSetString(0,name,OBJPROP_TEXT,"Leverage"+": "+string(AccountLeverage()));
}
name="AccFreeMarg"+identif;

if(ObjectFind(name)==-1)
{
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_CORNER,0);
ObjectSetInteger(0,name, OBJPROP_XDISTANCE,20);
ObjectSetInteger(0,name, OBJPROP_YDISTANCE, 45);
ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(0,name, OBJPROP_COLOR, clrGreen);
}
ObjectSetString(0,"AccFreeMarg",OBJPROP_TEXT,"AccountFreeMargin"+": "+string(AccountFreeMargin()));



 return(rates_total);
  }
  
  
//////////////////////////////////////////////////////////////
void OnDeinit(const int reason)
{
string name_delete;
for(int i=ObjectsTotal()-1;i>=0;i--)
{
name_delete=ObjectName(i);
if(StringFind(name_delete,identif)!=-1) ObjectDelete(name_delete);
}

}

 

 As you can see is very convenient and concise.

 

1.8. check whether a warrant or modified closed

As we know, after the 600-th build MetaTrader when compiling steel pojavljatsja warning that it is necessary to check the open or close or modify an order.

Figure 1.8.1.

 

So. Why do it? Correctly! For cultural writing code! 

Theoretically, the opening-closing of the order is necessary to check for repeated attempts to open-close the order or cancel the opening of the order.

Figure 1.8.2. 


As we can see whether the warning disappeared after checking the order opened. 

In tsykl used repeated attempts to open an order if it does not open. If the order is opened or not opened because no grip available funds to open it, then attempts to re-order opening stop. 

In the case of modification of orders it is usually necessary to check whether the order is simply for cultural modified. In contrast to the opening and closing orders need to check the modification of orders can not see.

For example noloss function.

Example 1.8.1.

////////////////////////////////////////////////////////////////
void NoLoss_f()
{
  for (int i=OrdersTotal()-1; i>=0; i--) 
  {
  if(OrderSelect(i, SELECT_BY_POS)) 
  {
  if(OrderSymbol() == Symbol())
  { 
  if (OrderMagicNumber()==Magic)
  {
  while(IsTradeContextBusy()) Sleep(int(pause_if_busy*1000));
  RefreshRates();
  
      if (OrderType()==OP_BUY) 
      {
      if(OrderStopLoss()!=OrderOpenPrice()+NormalizeDouble(Bez_Ub_Size*point,Digits))
      {
      if (Bid>OrderOpenPrice()+Bez_Ub_Level*point && (OrderStopLoss()<OrderOpenPrice() || OrderStopLoss()==0)) 
      {
      if(OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+NormalizeDouble(Bez_Ub_Size*point,Digits),OrderTakeProfit(),0,clrNONE))
      continue;       
      }
      }
      }
      else
      if (OrderType()==OP_SELL) 
      {
      if(OrderStopLoss()!=OrderOpenPrice()-NormalizeDouble(Bez_Ub_Size*point,Digits))
      {
      if (Ask<OrderOpenPrice()-Bez_Ub_Level*point && (OrderStopLoss()>OrderOpenPrice() || OrderStopLoss()==0)) 
      {
      if(OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-NormalizeDouble(Bez_Ub_Size*point,Digits),OrderTakeProfit(),0,clrNONE))
      continue;
      }
      }  
      }   
  }
  }
  }
  }
}

 

 In this function, if the order is modified we will use continue, ie we move on to the next iteration of the operator. In fact, we start to work with the next order.

 

 

Conclusion

So we discussed examples of cultural writing code.

If you carefully write code, then it will save resources Computer peripherals and code readability.

Share it with friends: