English Русский 中文 Español Deutsch Português
preview
アプリケーションを使用してMQL5の関数を理解する

アプリケーションを使用してMQL5の関数を理解する

MetaTrader 5トレーディング | 11 8月 2023, 08:01
444 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

はじめに

プログラミングの世界では、あらゆるソフトウェアにおいてその重要性から頻繁に使用され、よく聞かれる非常に人気のある用語があります。「関数」です。この記事では、関数について詳しく学び、高機能で高品質なソフトウェアを作成する方法を学びます。関数とは何か、関数を使用する必要がある理由、アプリケーションで関数を使用する方法を理解するための重要なトピックを説明していきます。その後、この記事で学んだことを応用するための例として、あらゆる取引システムで使用できるいくつかの簡単な関数を紹介します。この興味深いトピックを取り上げるために本稿で共有する主なアイデアは次のとおりです。

免責条項:すべての情報は「現状有姿」で提供され、情報提供のみを目的としており、取引目的やアドバイスを目的としたものではありません。いかなる結果も保証するものではありません。読者がこれらの資料を自分の取引口座で使用する場合、自己責任でおこなってください。


関数の定義

この部分では、プログラミングにおける関数とその種類、および関数を使用する必要がある理由を特定します。関数は、意味のある表現名で宣言されたコードのブロックであり、特定のタスクを実行するために何度も呼び出すことでソフトウェアの他の部分で使用できます。ソフトウェアの多くの部分または多くのソフトウェアで実行される特定のタスクがある場合、このタスクを実行するための関数またはコードブロックを作成し、それを呼び出します。後で書き直す場合は、コード全体ではなく、この部分のみを書き直します。関数は、この記事で説明するように、多くの乱雑なコードを使用せずにコードを抽象化する方法であると言えます。関数には主に組み込み関数とユーザー定義関数の2つのタイプがあります。組み込み関数がプログラミング言語自体による既製の関数である一方、ユーザー定義関数は、ユーザーが自分のニーズやソフトウェアで実行する必要があるタスクに応じて作成できる関数です。この記事ではユーザー定義関数に焦点を当てます。このタイプについて詳しく学び、このタイプの関数を使用する必要がある理由​​、その重要性や使用の特徴を理解していきます。

資本が最大ドローダウンに達した場合にすべてのオープン注文をクローズするタスクを実行するソフトウェアが必要で、このタスクをソフトウェアの多くの部分で実行する必要があるとします。この場合、関数を作成し、このタスクを実行するために必要なコードまたはロジックをすべて含めてから、他の部分でこの関数を呼び出す方が良いでしょう。タスクを実行するために多くの部分で同じコードを記述して繰り返すのは、良いことではなく、手に負えなくなります。

なぜこのタイプの関数を使用する必要があるのかを尋ねる場合、この質問は、ユーザー定義関数を使用することの特徴を学ぶことにつながります。これは以下です。

  • DRY(do not repeat yourself、同じことを繰り返さない)の概念を適用するのに役立つ: ユーザー定義関数を使用すると、同じコードを何度も繰り返さずに、タスクを1回実行できる関数を作成してそれをソフトウェア内の適切な部分で呼び出すことができます。
  • 再利用性: 作成した関数は、いつでも再利用できます。
  • 分割統治の概念を適用するのに役立つ: ソフトウェアを作成するとき、問題を解決するためにコードが複雑になることがありますが、大きな問題を小さな問題に分割し、関数を通じてそれぞれを解決すれば、大きな問題を解決するという目的を達成するのに非常に役立ちます。
  • コードがより読みやすく、理解しやすくなる: 関数を使用すると、それぞれの関数が特定の問題を処理し、特定のタスクを担当するため、コードがより整理されて読みやすくなります。
  • 抽象化の概念を適用するのに役立つ: 関数を使用すると、コードを抽象化する方法が得られます。関数を使用しない場合、関数を使用するよりも多くのコード行を記述する必要があることが判明する可能性があるためです。
  • カプセル化の概念を適用するのに役立つ: 関数を使用すると、関数を使用しない場合よりもコードとデータを安全に管理できるようになります。
  • デバッグプロセスの改善: 関数を使用すると、エラーの調査と解決がはるかに簡単になり、改善に役立ちます。

これらの特徴により、ソフトウェアでこれらのユーザー定義関数を使用すると、どれだけのメリットがあるかが簡単にわかります。


関数の構造

この部分では、次の2つのステップを通じて、関数と関数の構造についてさらに詳しく学習します。

  • 関数の宣言または定義
  • 関数の呼び出し

まず、新しい関数を定義または宣言する必要があるため、次の構造のようなことをおこなう必要があります。

returnedDataType functionName(param1, param2)
{
        bodyOfFunction
}
  • returnedDataType:関数が実行後に返す必要があるデータの型
  • functionName:関数の名前(関数が実行するタスクに従って名前を付ける)
  • param1,param2:変数またはプレースホルダー(いずれも指定しない場合に必要)を追加
  • bodyOfFunction:タスクを実行するすべてのコードを指定 

これを簡単な例に適用してみましょう。2つの値の加算タスクを実行する単純な関数は、次のコードブロックを通じて作成できます。

//addition function
// returned data type is an integer - the name of the function is add - parameters or arguments are two int variables val1 and val2
int add(int val1, int val2)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of val1 and val2 addition
   int result = val1+val2;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

関数を定義した後、関数を呼び出すという2番目のステップを実行します。これをおこなうには、関数の名前を呼び出し、ソフトウェアコードの必要な部分で関数に従って必要なパラメータを指定します。例に戻り、関数を呼び出したい場合は、次のようになります。

   //calling our defined function by its name and specifying arguments
   add(5,15);

これを呼び出すと、次の図のように、関数と指定された引数に従って[エキスパート]タブに値の結果「20」が表示されます。

add関数の結果

前の例は関数を使用して何ができるかの例にすぎませんが、関数で使用できる特性は多数あります。以下にその一部を示します。

引数付き関数

add関数の例では、val1とval2という2つの整数変数を使用しました。これらの変数は関数の引数として考慮されます。引数には、整数、文字列などのデータ型を指定できます。前の例では見ての通り整数変数でしたが、以下の別の例では文字列引数を見ることができます。

//sayHello function
// returned data type is string - name of function is sayHello - parameters or arguments are two string variables greeting and name
string sayHello(string greeting, string name)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string result = greeting+name;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

この関数は前と同じように呼び出すことができます。実行後の結果は次のようになります。

Sayhello関数の結果

関数の本体を実行するためのパラメータまたは引数として関数内で必要なものに応じて、これらのデータ型を組み合わせることもできます。引数の数は、ニーズに応じて変えられます。

引数のない関数

関数はパラメータや引数を指定せずに宣言または定義することもできます。また、関数に意味のある名前を付けて引数を空のままにして、タスクを実行する関数の本体を入力して完了し、引数を指定せずに関数を呼び出すこともできます。次が例です。

//sayHello function
// returned data type is a string - the name of the function is sayHello - no parameters
string sayHello()
  {
   //body of the function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string greeting= "Hello, ";
   string name= "World!";
   string result = greeting+name;
   //Print the result in the experts' tab
   Print(result);
   //returning value
   return result;
  }

関数の呼び出しは次のようになります。

sayHello();

関数の本体が同じであるため、結果は引数付き関数で前述したものと同じになります。

デフォルト値を持つ関数

この場合も、関数を定義し、パラメータの初期値またはデフォルト値を指定しますが、それらを希望の値で変更または更新することもできます。同じ例を適用すると、これは次のようになります。

//defining function with default values
string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

次に、関数を2回呼び出して、デフォルト値の違いを識別し、それらを更新するかどうかを確認できます。パラメータを更新する場合はパラメータを指定できますが、パラメータを指定しない場合、関数はデフォルト値を返します。以下のようになります。

   sayHello();
   sayHello("Hi, ", "Developer!");

結果は次のようになります。

Sayhello関数のdef値の結果

パラメータの受け渡し

関数には値を渡すことができます。これらの値は、前述したように、int、string、arrayなどの任意の型のデータにすることができます。パラメータの値渡しでは、元の変数は関数内で変更されず、パラメータの値を関数に渡したときと同じままです。元の変数を更新する必要がある場合は、関数にパラメータを参照渡しすることができます。

以下は、参照渡しについて述べたことを理解するための簡単な例です。

//passing by reference
void updateNums(int &val1, int &val2)
  {
   val1*=2;
   val2/=2;
  }

次に、新しい変数を作成してその値を出力し、これらの新しい変数をパラメータとして関数を呼び出し、呼び出し後にその値を出力して差を表示します。

//new variables
   int firstNum = 10;
   int secondNum = 20;
   
//before calling function
   Print("before calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 
   
// calling   
   updateNums(firstNum, secondNum);

// after calling  
   Print("after calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 

2つの出力の結果ですが、最初の出力は新しい変数10と20の値になり、呼び出し後は、関数の本体に従って更新された20と10後の値になります。結果は次のようになります。

参照渡し

return演算子

値を返す関数がある場合は、return演算子が必要です。関数タスクに基づいて関数内に複数のreturn演算子を含めることができますが、関数が値を返す場合は、関数の最後の行に少なくとも1つのreturnが必要です。このreturn演算子は任意の型にすることができますが、配列にすることはできません(配列からの要素を返すことはできます)。関数が配列を返すようにしたい場合は、前に述べたように、参照によって配列を関数に渡すことができます。

以下は、以前に述べたreturn演算子を含む例です。

string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

void型関数

関数が値を返さない場合はvoid型関数を使用します。この型は値を返さないためです。このタイプの関数には通常通り引数を渡すことができますが、return演算子は必要ありません。以下はこのタイプの関数の例です。

void add(int val1, int val2)
  {
   int result= val1+val2;
  }

関数のオーバーロード

関数を定義する場合、同じタスクを異なる引数で実行するために、同じ名前で多くの関数を定義する必要がある場合があります。たとえば、加算タスクがあるが、この加算を2つの値に対して実行する必要があって同じタスクを3つの値に対して実行する必要がある場合、同じ関数名で2つの関数を作成して、タスクに従ってパラメータを変更します。これは、オーバーロード関数があることを意味します。つまり、オーバーロード関数は、異なる引数で同じタスクを実行する関数です。

これらの異なる引数には、異なるデータ型の引数、同じデータ型の数値、またはその両方を指定できます。以下は、同じデータ型で引数の数が異なるオーバーロード関数の例です。

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(int val1, int val2, int val3)
{
   int result=val1+val2+val3;
}

ご覧のとおり、同じ関数がありますが、引数が異なります。関数を呼び出そうとして関数の名前を入力すると、これら2つの関数が表示されるので、タスクの詳細に従って必要なものを選択できます。以下は、データ型ごとに異なる引数を使用したオーバーロード関数の例です。

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(string message, int val1, int val2)
{
   int result=message+val1+val2;
}

関数を呼び出すときに引数に従って必要な関数を選択することもできます。


関数の使用

この部分では、この関数を使用してユーザー定義関数の利点を活用し、コーディングプロセスを容易にする簡単なアプリケーションを作成します。これらのアプリケーションを作成した後、ソフトウェアの別の部分で呼び出したり、アプリケーションを含めることで別のソフトウェアで呼び出すこともできます。

ニュースアラートアプリ

経済ニュースの最中に取引するのは非常に危険であることは誰もが知っていますし、ニュース中には取引しないようにという専門的なアドバイスもたくさんあります。ご存じない場合、経済指標カレンダーはマクロ経済のニュースと指標、説明、日時、重要度、これらの経済イベントの発表値が含まれる既製のカレンダーです。市場に影響を与える可能性のあるこれらの重要な値を更新し、それに基づいて取引するために使用できるソースは数多くあります。このカレンダーはMetaTrader 5取引ターミナルにも含まれており(ツールボックスウィンドウにそのタブがあります)、重要性、通貨、国に関して何を表示するかを制御できます。経済指標カレンダーを操作するための組み込み関数もあります。次のリンクからMQL5ドキュメントですべてを確認できます。

経済指標カレンダー関数

ニュース経済指標カレンダーを手動で確認してニュース中の取引を避けるかニュースが近づいたら取引を停止するように警告するアプリを作成します。このタスクは永続的であるため、どの取引システムやソフトウェアの多くの部分でも必要になります。したがって、そのための関数を作成して簡単に呼び出すことができます。この部分では、次の手順に従ってこれを実行します。

このアプリはEAになります。グローバルスコープでは、bool型関数isNewsComingを作成し、パラメータは追加しません。

bool isNewsComing()

関数の本体では、MqlCalendarValue型のvaluesという配列を作成します。これは、たとえば実際の値のようなニュースリリースの値になります。

MqlCalendarValue values[];

新しいdatetime型変数startTimeを宣言した後、iTimeを使用してバーの開く時刻を返し、一日の開始時刻を定義します。新しいdatetime型変数endTimeを宣言した後、その日の終了時刻を、定義された開始時刻とその日の秒数(PeriodSeconds関数を使用)を足したものに等しく定義します。

   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);

定義された開始時刻と終了時刻を使用して時間範囲を決定し、CalendarValueHistory関数を使用して現在の国と通貨で並べ替えることにより、その日のすべてのイベントの値の配列を取得します。引数は値の配列、開始時刻、終了時間、国、通貨です。

CalendarValueHistory(values,startTime,endTime,NULL,NULL);

ループを作成します。このループは、作成されたint型変数「i」の値(0)から開始され、「i」が値配列の配列サイズより小さい場合はループを継続し、「i」を1つインクリメントします。

for(int i=0; i<ArraySize(values); i++)

forループの本体ではevent変数を作成します。その型はイベントを記述するMqlCalendarEventであり、CalendarEventByIdで使用できます。

MqlCalendarEvent event;

CalendarEventByIdを使用してIDによってイベントの説明を取得します。その引数は、event_idとeventです。

CalendarEventById(values[i].event_id,event);

country変数を作成します。その型は国を記述するMqlCalendarCountryになり、CalendarCountryByIdとともに使用できます。

MqlCalendarCountry country;

MqlCalendarCountry関数を使用してIDによって国の説明を取得します。その引数はcountry_idとcountryです。

CalendarCountryById(event.country_id,country);

現在の銘柄や通貨ニュース、ニュースの重要度(中または高)、他に継続しているものがあるかどうかでイベントをフィルタリングする条件を設定します。

      if(StringFind(_Symbol,country.currency)<0)
         continue;

      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;

必要なアラートの時間範囲をニュース時刻の30秒前にする条件を設定します。

      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))

次に、イベント名と「is coming!Stop Trading...」というテキストを含むメッセージを[エキスパート]タブに出力します。

Print(event.name, " is coming! Stop Trading...");

戻り値はtrueになります。

return true;

条件がfalseの場合、ループを終了し、falseを返して関数を終了します。

return false;

次に、OnTick関数で関数を呼び出し、trueが返された場合は、「News is coming...!」という出力メッセージが必要になります。

   if(isNewsComing())
     {
      Print("News is comming...!");
     }

これで、関数を作成して呼び出しました。必要に応じてソフトウェアのどの部分でも使用できます。以下は、1つのブロック内の完全なコードです。再度読みやすくするために、すべてのアプリケーションのソースコードファイルはは記事に添付されています。

//+------------------------------------------------------------------+
//| News Alert Function                                              |
//+------------------------------------------------------------------+ 
void OnTick()
  {
   if(isNewsComing())
     {
      Print("News is comming...!");
     }
  }
//+------------------------------------------------------------------+
bool isNewsComing()
  {
   MqlCalendarValue values[];
   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);
   CalendarValueHistory(values,startTime,endTime,NULL,NULL);
   for(int i=0; i<ArraySize(values); i++)
     {
      MqlCalendarEvent event;
      CalendarEventById(values[i].event_id,event);
      MqlCalendarCountry country;
      CalendarCountryById(event.country_id,country);
      if(StringFind(_Symbol,country.currency)<0)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;
      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))
        {
         Print(event.name, " is coming! Stop Trading...");
         return true;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+

ロットサイズ計算アプリ

リスク割合とピップ単位の最大損失を決定した後に最適なロットサイズを計算できるアプリを作成します。また、リスク割合とエントリ価格とストップロス価格を決定した後に最適なロットサイズを計算するオーバーロードされた関数も作成します。次の手順のように、このアプリをスクリプトとして作成します。

double型のOptimalLotSize関数を作成します。最初の関数の引数は2つで、最大リスク割合のdouble変数、およびピップ単位の最大損失のdouble変数になります。

double OptimalLotSize(double maxRiskPrc, double maxLossInPips)

次に、これらの引数に対して何を実行するかを指定します。まず、適切な口座プロパティ(ここでは口座エクイティのID、ENUM_ACCOUNT_INFO_DOUBLE)の値を返すAccountInfoDouble関数を使用して口座エクイティ値を定義します。値を使用してアラートを作成します。

   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);

SymbolInfoDouble関数を使用して、銘柄の契約サイズを定義します。この関数は、指定された銘柄の対応するプロパティを銘柄の名前のバリアント(_Symbol)で返し、現在の銘柄とprop_id(ENUM_SYMBOL_INFO_DOUBLE値の1つであるSYMBOL_TRADE_CONTRACT_SIZE)を返します。その後、この戻り値のアラートが必要になります。

   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);

ピップ値を計算し、その値を含むアラートを作成します。

   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);

定義された口座エクイティからの損失の最大値を計算し、この値を含むアラートを作成します。

   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);

計算された最大損失額に基づいて相場通貨での最大値を計算し、この値を含むアラートを返します。

   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);

最適なロットサイズを計算し、その値を含むアラートを返します。

   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);

return演算子はOptimalLotSizeをdouble型の値として返します。

return OptimalLotSize;

その後、最大リスク割合、エントリ価格、ストップロス価格の3つのdouble型引数を渡してオーバーロード関数を作成します。

double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)

エントリ価格とストップロス価格の入力引数に基づいて絶対値として最大損失をピップ単位で定義し、0.0001で割ります。

double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;

return演算子は、最大リスク割合とピップ単位の最大損失を引数として作成されたOptimalLotSize関数になります。

return OptimalLotSize(maxRiskPrc,maxLossInPips);

次に、必要に応じてOnStart()部分の2つの関数のいずれかを呼び出すことができます。たとえば、次のようになります。

OptimalLotSize(0.01, 1.12303, 1.11920);

以下は、このタイプのアプリを作成するためにこのタイプの関数を作成する完全なコードです。

//+------------------------------------------------------------------+
//| lotSize Calc Function                                            |
//+------------------------------------------------------------------+
void OnStart()
  {
   OptimalLotSize(0.01, 1.12303, 1.11920);
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double maxLossInPips)
  {
   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);
   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);
   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);
   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);
   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);
   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);
   return OptimalLotSize;
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)
  {
   double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;
   return OptimalLotSize(maxRiskPrc,maxLossInPips);
  }
//+------------------------------------------------------------------+

このスクリプトを実行すると、次のアラートが表示されます

ロットサイズアプリ

前述のアプリケーションのように、コードを再度書き直すことなくタスクを実行するために、さまざまなソフトウェア部分で簡単に使用および呼び出しできるLotSizeCalc関数があります。

完全決済アプリ

ここでは、このタスクを実行するためにソフトウェアの適切な部分で使用または呼び出しできる関数を作成することにより、オープン注文と未決注文を閉じることができるスクリプトを作成します。次の手順を使用します。

プリプロセスまたは#includeを使用してTradeクラスをコードに組み込み、すべての取引関数をTrade.mqhファイルに含めます。

#include <Trade/Trade.mqh>

ソフトウェアで使用するために、CTradeクラス型のオブジェクトを作成します。

CTrade trade;

グローバルスコープでも、引数なしでvoid closeAll関数を作成します。

void closeAll()

関数の本体では、オープン注文を確認するためのforループを作成します。

for(int i=PositionsTotal()-1; i>=0; i--)

 ループの本体。ulongposTicket変数を作成し、オープン注文のチケットをそれに割り当てます。

ulong posTicket=PositionGetTicket(i);

trade.PositionClose(posTicket)を使用して開いた取引を決済します。

trade.PositionClose(posTicket);

未決注文を削除するには、これらの注文を検出するための別のforループを作成し、そのチケットをposTicketのulong変数に割り当て、検出されたチケットによって未決注文を削除します。

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }

その後、この関数をOnStart()部分で呼び出します。

closeAll();

このスクリプトを実行すると、すべての注文が閉じられ、削除されます。以下は、このcloseAllAppを1つのブロックで作成する完全なコードです。

//+------------------------------------------------------------------+
//| closeAll Function                                                |
//+------------------------------------------------------------------+ 
#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
void OnStart()
  {
   closeAll();
  }
//+------------------------------------------------------------------+
void closeAll()
  {
//close all open positions
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong posTicket=PositionGetTicket(i);
      trade.PositionClose(posTicket);
     }
//delete all pending orders
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }
  }
//+------------------------------------------------------------------+

これらのアプリケーションは、ユーザー定義関数として作成できるものの例にすぎず、それらを開発したり、トレーリングストップや取引管理アプリケーション、ドローダウンセーフティツールなど、ニーズに応じて他のアプリケーションや関数を作成したりすることができます。


結論

この記事で述べたことに基づき、ソフトウェアで関数を使用することで得られるすべての機能と利点を考えると、関数を使用することが重要であることがお分かりかと思います。

  • DRY(同じことを繰り返さない)の概念をプログラミングに適用するのに役立つ
  • 小さな問題に分割して対処することで、大きな問題を最小限に抑える
  • コードを読みやすくする
  • 再利用性
  • コードの抽象化
  • コードのカプセル化
  • デバッグの改善

また、関数の構造と関数のすべての特性(パラメータまたは引数を渡せる引数付き関数、引数なし関数、デフォルト値を使用する関数)を学習することで、関数とは何か、そのタイプ(組み込み関数とユーザー定義関数)、関数を作成または定義する方法をよく理解できたと思います。任意のデータ型を使用して関数を定義し、それに基づいてreturn演算子を処理できること、および同じタスクを実行するために同じ名前で引数が異なる多数のオーバーロード関数を作成する方法もお分かりになったと思います。

例として関数を作成して3つの異なるアプリケーションを共有したことが、トピックの理解を深めるのに大いに役立ったと思います。

  • 新しいアラートアプリ:重要なニュースが来たときにアラートを受け取るために、ソフトウェアの任意の部分で使用または呼び出されます(newsAlertAppソースコード添付)。
  • ロットサイズ計算アプリ:ソフトウェアの任意の部分で使用または呼び出され、定義されたリスク割合、エントリ価格、ストップロス価格に基づいて、または、定義されたリスク割合とピップ単位の最大損失に基づいて、取引を開始するための最適なロットサイズを返します。つまり、このアプリではオーバーロード関数を作成しました(LotSizeCalcAppソースコードが添付)。
  • CloseAllApp:すべてのオープン注文と未決注文を閉じるために使用または呼び出されます(closeAllAppソースコード添付)。

関数の世界は非常に興味深いものであり、有用なコードを簡単、スムーズ、効果的に作成できるようにするためには、関数に注意を払うことが非常に重要です。この記事が、読者のコーディングスキルを向上させ、取引をうまく進めるのに役立つ便利なツールを作成することで読者の取引キャリアを向上させるのに役立つことを願っています。プログラミングに関する記事や、移動平均、RSI、MACD、ストキャスティクス、ボリンジャーバンド、パラボリックSARなどの最も人気のあるテクニカル指標に基づいた取引システムの作成方法に関する記事をさらにお読みになりたい場合は、私の記事をチェックして、それに関する記事を見つけてください。同様に役立つことを願っています。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/12970

添付されたファイル |
newsAlertApp.mq5 (1.37 KB)
lotSizeCalcApp.mq5 (1.45 KB)
closeAllApp.mq5 (0.86 KB)
平均足と移動平均を組み合わせると良好なシグナルを提供できるのか 平均足と移動平均を組み合わせると良好なシグナルを提供できるのか
戦略を組み合わせることで、より良い機会が得られる可能性があります。指標やパターンを組み合わせたり、さらに良いことに指標とパターンを組み合わせたりして、追加の確認要素を得ることができます。移動平均はトレンドを確認し、それに乗るのに役立ちます。これらは、そのシンプルさと、分析に付加価値をもたらす実証済みの実績により、最もよく知られているテクニカル指標です。
MQL5のインタラクティブGUIで取引チャートを改善する(第2回):移動可能なGUI (II) MQL5のインタラクティブGUIで取引チャートを改善する(第2回):移動可能なGUI (II)
MQL5で移動可能なGUIを作成するための詳細なガイドで、取引戦略やユーティリティでの動的なデータ表現の可能性を引き出しましょう。オブジェクト指向プログラミングの基本原理を理解し、同じチャート上に単一または複数の移動可能なGUIを簡単かつ効率的に設計実装する方法を発見してください。
MQL5でのグラフィカルパネルの作成を簡単に MQL5でのグラフィカルパネルの作成を簡単に
この記事では、取引において最も価値があり役立つツールの1つであるグラフィカルパネルを作成する必要がある人に、シンプルで簡単なガイドを提供します。グラフィカルパネルは、取引に関するタスクを簡素化および容易にして、時間を節約し、気を散らすことなく取引プロセスそのものに集中するのに役立ちます。
Goertzelアルゴリズムによるサイクル分析 Goertzelアルゴリズムによるサイクル分析
この記事では、MQL5でGoertzel(ゲルツェル)アルゴリズムを実装するコードユーティリティを紹介し、このテクニックを価格相場の分析に利用し、可能な戦略を開発するための2つの方法を探ります。