エキスパート: トレーダーのためのMQL5プログラミング - 書籍からのソースコード。第7部 - ページ 3

 
ウェブソケット・クラスの バグ修正と改良をいくつか添付する。
ファイル:
wss.zip  16 kb
 
Stanislav Korotky #:
ウェブソケット・クラスの バグ修正と改良をいくつか添付します。
ご苦労様でした。
 
Stanislav Korotky #:
経済カレンダーの読み込みとCSVへのエクスポートに関するバグフィックスと改善がコード ベースで公開された。具体的には、ソートされた大きな配列(これは通常MQL5のカレンダーAPIから受信される)の場合のソートアルゴリズムが修正され、スローダウンやスタックオーバーフローがなくなった。

msclient.mqhの126行目'return connection.handshake(url, host, origin, custom_headers);'に'path'の代わりに完全な'url'を渡すと、pythonのwebsocketで403エラーになります。EAが私のpythonウェブソケットサーバに正常に接続できるようにするには、この変更を行う必要がありました。
Postmanのサーバーログ(合格)と変更前のEAのサーバーログ(失敗)を添付 します。

しかし、ここで次の問題が発生します。私のサーバーは設定された間隔で自動的にkeepalive pingを送信しますが、MT5のウェブソケット実装は応答しないようで、この動作が原因でサーバーはpingタイムアウトの直後にクライアント接続を常に切断します。

keepalive ping pongに関して何かヘルプがあればお願いします。

ファイル:
passed.png  88 kb
failed.png  50 kb
 
pauldic #:

msclient.mqhの126行目'return connection.handshake(url, host, origin, custom_headers);'に'path'の代わりに完全な'url'を渡すと、pythonウェブソケットでエラー403になる小さな芽があります。EAが私のpythonウェブソケットサーバに正常に接続できるようにするには、この変更を行う必要がありました。
Postmanのサーバーログ(合格)と変更前のEAのサーバーログ(失敗)を添付 します。

しかし、ここで次の問題が発生します。私のサーバーは設定された間隔で自動的にkeepalive pingを送信しますが、MT5のウェブソケット実装は応答しないようで、この動作が原因でサーバーはpingタイムアウトの直後にクライアント接続を常に切断します。

keepalive ping pongに関して何かヘルプがあればお願いします。

クライアントコールでpathを 使用することは可能です:

template<typename T>
class WebSocketClient: public IWebSocketObserver
{
   ...
   bool open(const string custom_headers = NULL)
   {
      ...
      connection = new T(&this, socket, compression);
      return connection.handshake(path, host, origin, custom_headers);
   }

一方、HTTPリクエスト構文はターゲットとして完全なURIをサポートしており、異なるサーバ(wss://ws.postman-echo.com/rawを 含む)に対してオリジナルのソースコードでテストを行いましたが、正常に動作しました。というわけで、ある意味違反なのか、あなたのpythonの実装が厳しすぎるのかはよくわかりません。

ping/pongに関しては動くはずです。wsprotocol.mqhを見て ください

   // PingでPongを送信し、Closeリクエストでコネクションを閉じる。
   void processControlFrame(IWebSocketFrame *frame)
   {
      switch(frame.getType())
      {
      case WS_FRAME_OPCODE::WS_CLOSE_FRAME:
         if(closeRequested) // クローズが確定
         {
            Print("Server close ack");
         }
         else if(!disconnecting) // サーバーがクローズを開始
         {
            if(openMessage) // まだ確定していない(!)
            {
               owner.onMessage(openMessage);
               openMessage = NULL;
            }
          
            WebSocketFrame temp(WS_FRAME_OPCODE::WS_CLOSE_FRAME); // アックを送る
            sendFrame(&temp);
         }
         close();
         break;
      case WS_FRAME_OPCODE::WS_PING_FRAME:
         {
            IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());
            sendFrame(temp);
            delete temp;
         }
         break;
      }
   }

サーバからクライアントにpingを送信しているのですから、あなたの側でデバッグしてください。

 
ところで、ws/sourcesで 使用しているMQL5Book/StringUtils.mqhの 新しいバージョンを追加するのを忘れていた。
ファイル:
 
Stanislav Korotky #:
ところで、ws/sourcesで 使用しているMQL5Book/StringUtils.mqhの 新しいバージョンを追加するのを忘れていた。
Stanislav Korotkyさん、ご協力ありがとうございました。pythonウェブソケットサーバーのping pong問題についてですが、デバッグを進めるうちに、サーバーがpingリクエストをテキストまたはバイナリデータとして送信し、MT5が正常に応答するのはテキストベースのpingが送信された場合のみであることに気づきました。



IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData(); IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData(); IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.

frame.getData() pingデータがテキスト/文字列ベースの場合のみ、サーバーはpongを認識するようですが、バイナリpingが送信された場合は失敗します
したがって、

両方のケースで動作するように、オーバーロードされたframe.getData(uchar &buf[]) を使用するようになりました。私の変更が)壊れるような他のユースケースに出会うかどうかはわからないが、今のところすべて問題なさそうだ。


uchar data[]
; frame.getData(data)
; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data); ちょっとした疑問なのですが、イベントハンドラ関数 OnMessage のようなものがある一方で、なぜ OnTimer() イベントハンドラでメッセージの有無を手動でチェックしなければならないのでしょうか。現在の設定はそのまま機能していますが、なぜこの方法なのか、詳しく教えていただけるとありがたいです。

 
pauldic #:
Stanislav Korotky ありがとうございます。python ウェブソケットサーバーの ping pong 問題について、デバッグを進めるうちに、サーバーが ping リクエストをテキストまたはバイナリデータとして送信し、MT5 が正常に応答するのはテキストベースの ping が送信された場合のみであることに気づきました。

IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData(); IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData(); IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.



frame.getData() pingデータがテキスト/文字列ベースの場合のみ、サーバーはpongを認識するようですが、バイナリpingが送信された場合は失敗します
したがって、

両方のケースで動作するように、オーバーロードされたframe.getData(uchar &buf[]) を使用するようになりました。私の変更が)壊れるような他のユースケースに出会うかどうかはわからないが、今のところすべて問題なさそうだ。


uchar data[]
; frame.getData(data)
; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data); ちょっとした疑問なのですが、イベントハンドラ関数 OnMessage のようなものがある一方で、なぜ OnTimer() イベントハンドラでメッセージの有無を手動でチェックしなければならないのでしょうか。現在の設定はそのまま動作していますが、なぜこの方法なのか、詳しく教えていただければ幸いです。

ご苦労様です。あなたの編集をソースコードに含めることを検討します。

OnTimerとOnMessageについては、あなたのアプリケーションで異なる処理ロジックを実装したいかもしれないので、提供されています。ソケットからの読み込みはMQL5のAPIレベルでブロッキングされ、タイムアウトが指定されます。したがって、新しいメッセージの待機、その処理、および応答の自動生成にのみ興味がある場合は、ブロッキングモードで実行できます(読み取り時のタイムアウトは無限で、OnTimerはありません)。しかし、ユーザーにレスポンシブなUIを提供する必要がある場合(チャットアプリの場合)、OnTimer-handlerで短い読み取り試行に対して小さなタイムアウトを設定し(タイムアウトした場合、空のデータを生成することができます)、その間のユーザーのアクションを監視します。

 
Stanislav Korotky #:

君の努力に感謝する。あなたの編集をソースコードに含めることを検討するよ。

OnTimerとOnMessageについては、アプリケーションで異なる処理ロジックを実装したい可能性があるため、提供しています。ソケットからの読み込みはMQL5のAPIレベルでブロッキングされ、タイムアウトが指定されます。したがって、新しいメッセージの待機、その処理、および応答の自動生成にのみ興味がある場合は、ブロッキングモードで実行できます(読み取り時のタイムアウトは無限で、OnTimerはありません)。しかし、ユーザーにレスポンシブなUIを提供する必要がある場合(チャットアプリの場合)、OnTimer-handlerで短い読み取り試行に対して小さなタイムアウトを設定し(タイムアウトした場合、空のデータを生成することができます)、その間のユーザーのアクションを監視します。

分かりやすい説明を ありがとうございました。
 

wss のソースコードを zip アーカイブに保存する際の細かいバグフィックスと改善です。

特に、アップグレードに失敗した場合(例えば、認証が必要で101以外のステータスコードが返された場合)を分析し、対策を講じることができるようになりました:

if(wss.open(initial_headers))
{
   // 成功、通常のフロー
}
else
{
  // アップグレードされていない、または接続されていない。
  if(wss.isConnected())
  {
     Print("Can't upgrade to websockets");
     bool resolved = false;
     string headers[][2]; // response
     if(wss.getHeaders(headers))
     {
       // TODO: ステータスを分析し、解決する。
       resolved = ... // 真/偽
     }
     if(!resolved)
     {
       wss.close(); // アップグレードされていないソケットからの読み取り/書き込みを防ぐためにクローズする。
     }
     else
     {
       wss.open(updated_headers); // try again
     }
  }
}

また、StringUtils.mqhURL.mqh も重要な修正を受けました。

ファイル:
wss.zip  16 kb
URL.mqh  5 kb
 

こんにちは、MQL5初心者 です。ウェブソケット用のwss.zipファイルを投稿しているのを見つけました。どのように使用するのでしょうか、デモや何か学べるものはありますか?ありがとうございました!

Stanislav Korotky
Stanislav Korotky
  • 2025.04.07
  • www.mql5.com
Trader's profile