MQLでstd::map

無駄な余談

MQL使っていると、単純なEA作っている分にはさほど気にはならないのですが、様々なEAやインジケーターを請負って開発代行していると見た目の機能は地味なのですが、実装すると超面倒なケースがめっちゃあります。

MQLはC++の構文をほぼ踏襲していると言えるほど、C++を使いこなしている人には非常に取り組みやすいです。

クラスはもちろん、派生クラスも使えるので私なんかはなんでもクラスにしちゃうの大好きなので実装そっちのけでクラス設計に気合入れてしまうほどです。(笑)

そして、超面倒なケースに遭遇したとき、とにかく頑張って何とかしなきゃいけないケースが多いです。
これが、MFCもありSTLもあるVC++を使いまくってた私としては、賛否はあるものの非常に便利だったことに気づかされます。

そして、私はstd::vectorやstd::listなどは自分でクラス作成して共通処理として使っていました。
ただ、テンプレートクラスまで作る程の汎用性のあるものを考えるには時間がなかったのでそこまで突き詰めていませんでした。

そしてふと思ったんです、std::vectorとかって自作してソース公開してるひといるんじゃね?
普通にC++で作られてたらMQLにポーティングしてやりゃいいし!
と思ったんです。

概要

やっと本題にはいりますが、見つけたんです
「MQL Foundation Library For Professional Developers」

「ふぁうんでぃしょん!」とか「らいぶらり」ってかいてある!

概要の癖に脱線しそうですが、要はstd::vectorやstd::mapみたいなライブラリを見つけたのです。
しかもMQL4/5という私の要望通りのものが。

※追記 2022/06/12
MQL5で使うとWarningでるようです。
MQL5ではこちらで対処する必要がありそうです。

ここでは、このライブラリの一部の機能であるHashMapについて説明します

ダウンロード

一般のファイルダウンロードと違って、zipでアーカイブされたものは多分ありません。
Gitをつかってご自身のPCにクローンを作成してください。
ちょっと、これは知らないとハードルがめちゃくちゃ高い気がしますが、私のここでの趣旨から逸脱するので省略します。

要は、Googleって人がそういう説明得意なんで聞いてきてください。

std::map

使い方準備

※MT4の場合
[データフォルダを開く]のメニューから
→MQL4
→include
→Mql
のフォルダにクローンを作成してください。
※ブランチは「master」で切り替えることもないでしょう。

インクルード

ソースの先頭のほうで下記のようにインクルードしてください。

#include <Mql/Collection/HashMap.mqh>

宣言

stringを検索キーにして、intを値とする場合の例で説明します。
※検索キーと値の説明は後程します。
ここでは、mapSampleで宣言します。

HashMap<string, int> mapSample;

「HashMap」宣言時の型だとお考え下さい。
<>内に

  1. 検索キー

の型を2つ並べて書きます。
検索キーとは、その名の通り検索で使うstring型(文字列)です。
値は、その検索キーに紐づけるint型の値(数値)です。
その後に変数名を指定します。

以下のように、

HashMap<int, string> mapSample;

という検索キーが数値のケースも使い方として想定できます。

格納

格納方法の例を以下に示します。

mapSample.set("aa", 1);
mapSample.set("aa", 2);
mapSample.set("bb", 3);

"aa"で2回、別の数値「1」「2」
"bb"で1回、「3」を格納してみました。

格納数

mapSampleに格納されたデータの数を調べるのは以下の構文となります。

int iSize = mapSample.size();

ここまでをデバック実行したとします。

結果はこうです。

「2」ですね。
お気づきでしょうか?
3回格納したのに2つになります。
これがHashMapの特徴で、検索キー1つに対して1つの値のみ関連付けることができます
"aa"で2回格納しているため、2回目で値が更新されます。

値取得(検索)

値の取得方法として一番使いそうな単純な方法を説明します。

例で示しますが、"bb"で検索して値を取得する場合です。
-1は存在しない場合の戻り値です。

int bb = mapSample.get("bb", -1);

またデバッグ実行で以下のコードのケースで見てみます。

"bb"は「3」
”aa"は「2」
になります。
先程説明しましたが、検索キーに対して一意の値になるため"aa"は2つ目に格納した「2」になっていることがわかります。
また、検索してくれるので取得する順番は自由です。

他にもいろいろなメソッド(関数)が用意されていますので全部クリアしたり、1つだけ削除といった機能も当然あります。
検索ではなく、1つ1つ順番に値を取り出すことも可能です。

応用方法

これが何に使えるかといわれると、ものすごくいろんなことに使えます。
ArrayResize()したりしなくて済みますし、最初から想定できる配列最大数でサイズを定義しておくといったスマートじゃないコードを書かなくて済むだけでだいぶ嬉しいです。

通貨と価格

通貨と価格を紐づけて記録しておく

HashMap<string, double> mapBid;
mapBid.set("USDJPY", Bid);
mapBid.set("EURUSD", 1.06323);

チケット番号とオーダー種類

口座内に存在するチケットを全て保持しておき、実際のポジション数と格納されているチケット数を比較して差が生じたときに何らかのアクションを行う場合に活用できます。

HashMap<int, int> mapTicket;
mapTicket.set(1, OP_BUY);
mapTicket.set(2, OP_SELL);
int iOrderType2 = mapTicket.get(2, -1);
int iOrderType1 = mapTicket.get(1, -1);

サンプルコード

今回紹介した使い方+αのサンプルを一気に公開しておきます。

void OnTick()
{
    HashMap<string, int> mapSample;
    mapSample.set("aa", 1);
    mapSample.set("aa", 2);
    mapSample.set("bb", 3);
    int iSize = mapSample.size();
    int bb = mapSample.get("bb", -1);
    int aa = mapSample.get("aa", -1);
    iSize = mapSample.size();
    aa = mapSample.pop("aa");
    iSize = mapSample.size();
    mapSample.clear();
    iSize = mapSample.size();
    aa = mapSample.get("aa", -1);

    HashMap<string, double> mapBid;
    mapBid.set("USDJPY", 130.125);
    mapBid.set("EURUSD", 1.06323);
    double dEURUSD = mapBid.get("EURUSD", -1);

    HashMap<int, int> mapTicket;
    mapTicket.set(1, OP_BUY);
    mapTicket.set(2, OP_SELL);
    int iOrderType2 = mapTicket.get(2, -1);
    int iOrderType1 = mapTicket.get(1, -1);
}

こんな技もできるのですが、C++ではありがちな応用です。

HashMap<string, HashMap<string, double>*> listFX;

void OnTick()
{
	HashMap<string, double>* FX = listFX.get("XMTrading-Demo3", NULL);
	if(CheckPointer(GetPointer(FX)) != POINTER_DYNAMIC) {
		listFX.set("XMTrading-Demo3", new HashMap<string, double>);
		FX = listFX.get("XMTrading-Demo3", NULL);
	}
	double dPrice = FX.get("USDJPY", -1);
	FX.set("USDJPY", 132);
	FX.set("EURUSD", 1.06);
}

上記のようなコードで動作するのは確認できたのですが、問題はHashMapをnewしているが、popしたときにちゃんとdeleteされるかが未確認です。
VC++で使ってた時はちゃんと勝手にdeleteされて、メモリリークは起きなかったのですが・・・
気が向いたらset、pop繰り返してメモリリーク起きないか調べておきたいところです。

最後に

今回はstd::mapに相当するHashMapを紹介しました。
std::mapとは若干使い方が違うのと、使い方に関してのリファレンスがあるわけでもなく、サイトにあるサンプルコードと実際のソースコード(.mqh)を覗いてみて使い方や使える機能を探るといったところが少し厄介ではありますが、それを差し引いても他にも使えそうな機能があるライブラリではないかと思いました。

こんなNote書いている最中も、ココナラでEA開発代行を請負っているので、依頼や見積りが来ているのですが、この便利な機能を先に使いこなせたら楽になりそうな、急がば回れではないかと思って使い方を調べてます。

この内容は、賛同頂けるかたから寄付を受け取るように有料としておりますが、寄付をしてこれ以降に情報は特にありません。
寄付はご先祖の遺言でちょっと・・・でも内容良かったよ!ってひとは、私のTwitterのフォローとイイねとリツイートをしておいてください。

ここから先は

56字

¥ 500

期間限定!PayPayで支払うと抽選でお得

この記事が気に入ったらチップで応援してみませんか?