Buy Limit Bracket

Author: Copyright 2020, Niclas Hummel Trading
Price Data Components
Series array that contains close prices for each bar
Orders Execution
It automatically opens orders when conditions are reachedChecks for the total of open orders
Indicators Used
Standard Deviation indicator
Miscellaneous
It issuies visual alerts to the screen
0 Views
0 Downloads
0 Favorites
Buy Limit Bracket
//+------------------------------------------------------------------+
//|                                            Buy Limit Bracket.mq4 |
//|                            Copyright 2020, Niclas Hummel Trading |
//|                                        https://niclashummel.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Niclas Hummel Trading"
#property link      "https://niclashummel.com/"
#property version   "1.21"
#property strict
#property show_inputs

#define INDEX uint   // Zero based.
#define COUNT uint   // One based.
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum enum_SwitchOnOff
  {
   ON=1,OFF=0
  };

double res1[];
double res2[][1000];
double corr[];

string currencies[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input double StDMultiplier = 1.0;            // Stop Multiplier (1.0 = unchanged)
input double LotMultiplier = 1.0;            // Lotsize Multiplier
input double TargetMultiplier = 2.0;         // Risk to Reward Multiplier (1:x Target)
input int stDPeriod = 30;                    // Standard Deviation Period for Stoploss
input int lookBack = 90;                     // Lookback Period for Correlation Coefficient
input enum_SwitchOnOff RiskPercentage = ON;  // Risk In Percentage ON/OFF
input double RiskPercent = 5.0;              // Riskpercentage of Accountbalance
input double RiskAmount = 50.00;             // Riskamount if Riskpercentage OFF
input int MagicNumber = 213891;              // Magic Number

double riskInCurr = 0.0;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
//--- resize Array to number of lookback period
   ArrayResize(res1,lookBack);
//--- execute long order
   _longOrder();
  }
//+------------------------------------------------------------------+
void _longOrder()
  {
//--- prepare variables for OrderSend()
   double stD = iStdDev(NULL,0,stDPeriod,0,MODE_SMMA,PRICE_CLOSE,1) * StDMultiplier;
   double stD2 = iStdDev(NULL,0,stDPeriod,0,MODE_SMMA,PRICE_CLOSE,1);
   double StopBPS = stD/Close[1];
   double stoplevel = MarketInfo(NULL,MODE_STOPLEVEL)*Point;
   double ask = MarketInfo(NULL,MODE_ASK);
   double tv = MarketInfo(NULL,MODE_TICKVALUE);
   double ts = MarketInfo(NULL,MODE_TICKSIZE);
   riskInCurr = RiskPercentage ? ((RiskPercent/100)*AccountBalance()) : RiskAmount;
   double _lotSize=NormalizeDouble(riskInCurr/(ask*StopBPS*(tv/ts)),(int)MarketInfo(NULL,MODE_DIGITS));

//--- check for minimum and maximum lot size
   if(_lotSize < SymbolInfoDouble(NULL,SYMBOL_VOLUME_MIN))
      _lotSize = SymbolInfoDouble(NULL,SYMBOL_VOLUME_MIN);
   if(_lotSize > SymbolInfoDouble(NULL,SYMBOL_VOLUME_MAX))
      _lotSize = SymbolInfoDouble(NULL,SYMBOL_VOLUME_MAX);

//--- _lotSize gets multiplied by correlation coefficients
   _lotSize *= calcCCs();

//--- _lotSize gets adjusted to Lotstep
   _lotSize = NormalizeDouble(MathFloor(_lotSize / MarketInfo(NULL,MODE_LOTSTEP)) * MarketInfo(NULL,MODE_LOTSTEP) * LotMultiplier,2);

   if(_lotSize == 0)
     {
      Alert("Lotsize can't be applied, because Minimum Lotsize risk goes over risk threshold. Reduce risk threshold and start again");
      ExpertRemove();
     }

   if(CheckMoneyForTrade(_lotSize,OP_BUYLIMIT))
     {
      if(!OrderSend(NULL,OP_BUYLIMIT,_lotSize,NormalizeDouble(ask-stD2,Digits),2,
                    NormalizeDouble(ask-stD2-stD,Digits),
                    NormalizeDouble(ask-stD2+stD*TargetMultiplier,Digits),(string)stD,MagicNumber))
         GetLastError();
     }
  }
//+------------------------------------------------------------------+
//| Checks if enough margin is available for opening the trade       |
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(double lots,int type)
  {
   if(lots < 0)
     {
      Alert("Can't open trade because correlations are too high");
      return false;
     }
   if(type%2==0)
      type=0;
   else
      type = 1;
   double free_margin=AccountFreeMarginCheck(Symbol(),type,lots);
//-- if not enough money
   if(free_margin<0)
     {
      Alert("Not enough money for " + (string)lots + " Lots in " + (string)Symbol() + " Error code = " + (string)GetLastError());
      return false;
     }
//-- check successfull
   return true;
  }
//+------------------------------------------------------------------+
//| Calculates correlation coefficients and takes into account, that |
//| there can be different initial stoplosses, that affect the       |
//| consideration weight of the correlation coefficient              |
//+------------------------------------------------------------------+
double calcCCs()
  {
//--- first create a series and fill res1 with current symbol for looking back lookBack period (=90)
   createSeriesThisSymbol();

   int count = 0;

//--- go through all orders
   for(int j = 0; j < OrdersTotal(); j++)
     {
      if(!OrderSelect(j,SELECT_BY_POS,MODE_TRADES))
         GetLastError();
      //--- only if it's not the same symbol, that the trade is made and if not already targeted
      if(OrderCloseTime() == 0 && OrderSymbol() != Symbol() && !isInCurrencyList(OrderSymbol()))
        {
         //--- resize res2 to amount of runs
         ArrayResize(res2,count+1);
         //--- fill res2, depending on the currency with close to close % returns
         for(int i = 0; i < lookBack; i++)
           {
            string Symbol2 = OrderSymbol();
            res2[count][i] = (iClose(Symbol2,0,i)-iClose(Symbol2,0,i+1))/iClose(Symbol2,0,i);
           }
         //--- resize currencies to amount of runs
         ArrayResize(currencies,count+1);
         //--- fill currencies to identifier = amount of runs (= amount of other currencies/symbols with open orders)
         currencies[count] = OrderSymbol();
         count++;
        }
     }

   int l = 0;

   int sizeRes2 = (int)ArraySize(res2)/1000;

//--- go through all symbols with open orders
   for(int k = 0; k < sizeRes2; k++)
     {
      //--- calculate correlation coefficient
      double cc = MathAbs(correlation_coefficient(res1,res2,k,lookBack));
      if(cc >= 0.1)
        {
         ArrayResize(corr,l+1);
         //--- save correlation coefficient in corr array
         corr[l] = cc;
         l++;
        }
     }

   double correlation_decrease_factor = 1.0;

   if(ArraySize(corr) >= 1)
     {
      //--- sort for highest correlation coefficient
      ArraySort(corr);
      for(int o = ArraySize(corr)-1; o >= 0; o--)
        {
         //--- calculate the amount that the position size should be reduced
         //--- takes into account the riskRatio = relation to initial full position size
         correlation_decrease_factor *= (1-corr[o]*riskRatio(currencies[o]));
        }
     }

   return correlation_decrease_factor;
  }
//+------------------------------------------------------------------+
//| This function calculates the ratio between the full currency     |
//| amount and the already invested initial risk in currency of the  |
//| open positions                                                   |
//+------------------------------------------------------------------+
double riskRatio(string OS)
  {
   return ((totalLots(OS) * stoploss_distance(OS) * MarketInfo(OS,MODE_TICKVALUE)) / MarketInfo(OS,MODE_TICKSIZE)) / riskInCurr;
  }
//+------------------------------------------------------------------+
//| Creates a series of close to close % returns                     |
//+------------------------------------------------------------------+
void createSeriesThisSymbol()
  {
   for(int i = 0; i < lookBack; i++)
     {
      res1[i] = (Close[i]-Close[i+1])/Close[i];
     }
  }
//+------------------------------------------------------------------+
//| Calculates correlation coefficient of two arrays                 |
//+------------------------------------------------------------------+
double correlation_coefficient(double& a[], double& b[][], int k, COUNT length, INDEX iBeg=0)
  {
   INDEX    iEnd  = iBeg + length;
   double   Ex=0.0,  Ex2=0.0,    Ey=0.0,  Ey2=0.0,    Exy=0.0;    // Ex=Sum(x)
   for(; iBeg < iEnd; ++iBeg)
     {
      double   x = a[iBeg],   y = b[k][iBeg];
      Ex += x;
      Ex2 += x * x;
      Ey += y;
      Ey2 += y * y;
      Exy += x * y;
     }
   double   ssxy  = length * Exy - Ex * Ey;
   double   ssxx  = length * Ex2 - Ex * Ex;
   double   ssyy  = length * Ey2 - Ey * Ey;
   double   deno  = MathSqrt(ssxx * ssyy);
   return (deno == 0.0) ? 0.0 : ssxy / deno;
  }
//+------------------------------------------------------------------+
//| Checks if the OrderSymbol os in the argument is in the currencies|
//| array                                                            |
//+------------------------------------------------------------------+
bool isInCurrencyList(string os)
  {
   for(int i = 0; i < ArraySize(currencies); i++)
     {
      if(os == currencies[i])
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Calculates the stoploss distance between the initial stoploss    |
//| and the current average price                                    |
//+------------------------------------------------------------------+
double stoploss_distance(string OS)
  {
   double avge=1, avge_sl = 1, Avgprice=0, Avgprice_sl=0, lts=0;

//--- saves open buy and sell orders in count variables
   int longcount = countOrders(OP_BUY,OS);
   int shortcount = countOrders(OP_SELL,OS);
   if(longcount == 0 && shortcount == 0)
     {
      longcount = 1;
      shortcount = 1;
     }

   string ordercomment = "";

//--- finds the ordercomment with the initial stoploss (when opened by my script with MagicNumber)
   for(int i = 0; i<=OrdersTotal(); i++)
     {
      if(!OrderSelect(i,SELECT_BY_POS))
         GetLastError();
      if(OrderType() < 2  && OrderSymbol() == OS && OrderMagicNumber() == MagicNumber)
        {
         ordercomment = OrderComment();
         break;
        }
     }

//--- if more long orders
   if(longcount > shortcount)
     {
      //--- first calculate total Lots
      for(int i = 0; i<=OrdersTotal(); i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS))
            GetLastError();
         if(OrderType() == OP_BUY  && OrderSymbol() == OS)
           {
            lts+= OrderLots();
           }
        }

      //--- then calculate the average entry price and stoploss
      for(int h = 0; h<=OrdersTotal(); h++)
        {
         if(!OrderSelect(h,SELECT_BY_POS))
            GetLastError();
         if(OrderType() == OP_BUY  && OrderSymbol() == OS)
           {
            Avgprice+= OrderOpenPrice() * (OrderLots() / lts);
            Avgprice_sl+= OrderStopLoss() * (OrderLots() / lts);
           }
        }

      avge = NormalizeDouble(Avgprice,(int)MarketInfo(OS,MODE_DIGITS));
      avge_sl = NormalizeDouble(Avgprice_sl,(int)MarketInfo(OS,MODE_DIGITS));
     }
//--- if more short orders
   else
     {
      //--- first calculate total Lots
      for(int u = 0; u<=OrdersTotal(); u++)
        {
         if(!OrderSelect(u,SELECT_BY_POS))
            GetLastError();
         if(OrderType() == OP_SELL  && OrderSymbol() == OS)
           {
            lts+= OrderLots();
           }
        }

      //--- then calculate the average entry price and stoploss
      for(int j = 0; j<=OrdersTotal(); j++)
        {
         if(!OrderSelect(j,SELECT_BY_POS))
            GetLastError();
         if(OrderType() == OP_SELL && OrderSymbol() == OS)
           {
            Avgprice+= OrderOpenPrice() * (OrderLots() / lts);
            Avgprice_sl+= OrderStopLoss() * (OrderLots() / lts);
           }
        }
      avge = NormalizeDouble(Avgprice,(int)MarketInfo(OS,MODE_DIGITS));
      avge_sl = NormalizeDouble(Avgprice_sl,(int)MarketInfo(OS,MODE_DIGITS));
     }
   if(avge == 1)
      avge = 0.0;
   if(avge_sl == 1)
      avge_sl = 0.0;

   double oc = (double)ordercomment;

//--- if no order was opened there's no initial stoploss, so take the average stoploss
   if(oc == 0)
     {
      return MathAbs(avge_sl-avge);
     } else {
      return oc;
     }
  }
//+------------------------------------------------------------------+
//| Counts all orders with certain OrderType in certain Symbol       |
//+------------------------------------------------------------------+
int countOrders(int oType,string OS)
  {

   int count=0;

   for(int i=0; i<OrdersTotal(); i++)
     {
      if(OrderSelect(i,SELECT_BY_POS))
        {
         if(OrderSymbol()==OS)
           {
            if(OrderType()==oType || oType<0)
              {
               count++;
              }
           }
        }
     }

   return count;
  }
//+------------------------------------------------------------------+
//| Returns total Lots for certain Symbol of open orders             |
//+------------------------------------------------------------------+
double totalLots(string OS)
  {
   double lts = 0.0;
   for(int i = 0; i<=OrdersTotal(); i++)
     {
      if(!OrderSelect(i,SELECT_BY_POS))
         GetLastError();
      if(OrderType() < 2  && OrderSymbol() == OS)
        {
         lts+= OrderLots();
        }
     }

   return lts;
  }
//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---