English Русский Español Português
preview
市場シミュレーション(第10回):ソケット(V)

市場シミュレーション(第10回):ソケット(V)

MetaTrader 5 |
23 0
Daniel Jose
Daniel Jose

はじめに

前回の「市場シミュレーション(第10回):ソケット(IV)」では、xlwingsとPythonをExcelに統合する機能について説明しました。一見すると、この内容は私たちが扱うレプリケーション/モデリングシステムには遠い話に思えるかもしれません。そして、PythonとExcelを組み合わせることに尻込みする前に、xlwingsを使ってExcelからMetaTrader 5をある程度操作できる方法を見てみましょう。ここで紹介する内容は主に教育目的ですが、もちろん、ここで取り上げることだけに制限されるわけではありません。実際にはさらに多くのことができます。ただし、そのためには、xlwingsがPythonを通してExcelをどう操作するのかを理解する必要があります。これが、Excelを直接操作せずにPython経由でMetaTrader 5を完全に制御するための唯一の方法だからです。結果として、PythonからMetaTrader 5を自在に操作できるようになります。


基礎から始める

まずは、とてもシンプルなことをやる必要があります。これは確実に動作するものです。最初に、xlwingsのドキュメントにある例を使いますが、少し違った説明の仕方で進めます。こうすることで、なぜExcelの中でPythonを実行できるのかが理解できるようになります。

まずは、最も簡単なところから始めましょう。任意のエディタで、下の画像に示したPythonコードを書き、保存します。

画像内のいくつかのポイントに注意してください。たとえば、どこにファイルを保存しているかなどです。しかし最も重要なのはファイル名です。この名前は後で非常に重要になります。このPythonスクリプトは何かを参照していることに注目してください。今回の場合は、Excelのスプレッドシートを参照しています。しかし、どのシートかはまだ特定できません。心配いりません。ステップごとに見ていきましょう。まず、05行目では特定のセルにテキストを書き込むことに注目してください。

ただし、このコードが動作するためには、スプレッドシートがExcelで開かれている必要があります。これは04行目に関係しています。この行が接続を確立し、どのシートにテキストを書き込むかを判断しています。次に、Excelを開き、新しいシートを追加します。こうすると、Excelは下の画像のような状態になります。

ここで注目してください。現在、Excelでは1つまたは複数のシートを選択できます。これは、Sheet1を選択したときに実行されるマクロを作成するためです。こうすることで、マクロを呼び出す際に余計な操作を追加せずに済みます。単にALT + F11でExcel VBAを開き、下の画像に示したコードを入力します。

このコードはSheet1に属していることに注意してください。これを有効にすると、このVBAスクリプトが実行されます。次にコードの03行目を見てみましょう。この行を正しく処理するためには、xlwingsへの参照を追加する必要があります。前回の記事でその方法を説明しました。xlwingsを参照したら、Pythonスクリプトを実行できるようになります。でも、どうやって実行するのでしょうか。

ご覧の通り、ここでは最初の画像で保存したファイルをインポートしています。VBAがどこにファイルがあるかを認識するには、ディレクトリとファイル名を指定する必要があります。ただし、スプレッドシートが同じディレクトリに保存されている場合は、ディレクトリの指定は不要です。

さらに、VBA(正確にはxlwings)に、Pythonスクリプトのどの部分を実行するかを指定する必要があります。これはセミコロンの後でおこないます。その後、Excelに戻って別のシートに切り替えると、結果は下の画像のようになります。

完璧です。これで、PythonがExcel内でタスクを実行できることを確認できました。VBAの多くの役割をPythonが置き換えられることになります。「多く」と言ったのは、Pythonで記述した内容を実行するには、まだ一部でVBAの操作が必要だからです。

では、これがMetaTrader 5とどう関係するのでしょうか。安心してください、もうすぐ説明します。Pythonに慣れていなければ、ここまでやったことは一見すると些細に思えるかもしれません。しかし、Pythonを学習中、あるいは既にプログラムしているのであれば、このシンプルな「Hello, World」が開く可能性に目が輝いたのではないでしょうか。

さて、書き込めるのであれば、読み込むことも可能です。前に、RTDやDDEサーバーを使ってExcelにデータを送るだけでは時間の無駄だと言ったことを覚えていますか。その場合、情報はExcelに送られるだけで、Excelで計算した結果をMetaTrader 5の制御に使うことはできません。

しかし、Pythonを使えば、Excelに直接データを書き込み、読み込むことができます。これにより、少し先のことを考えられるようになります。つまり、Excelからエキスパートアドバイザー(EA)を制御することが可能になります。そのためには、ExcelとMetaTrader 5の間に通信の橋を作るだけで済みます。もちろん、Excelを使わなくても、Pythonだけで同じことが可能です。

ただし、一部のトレーダーはチャートをほとんど見ません。価格だけで判断します。そして、ファンダメンタル指標を分析する最適な方法は何でしょうか。そうです、Excelのスプレッドシートです。しかし、Excelだけではなく、他のツールも併用する必要があります。今回のテーマでは、まず基礎に焦点を当てます。これは、次回作る別の仕組みを構築するための土台となるからです。


ExcelとMetaTrader 5の接続を計画する

ExcelとMetaTrader 5を接続するためには、効率的で実装しやすい方法が必要です。その中でも最適な方法のひとつがソケットの利用です。ソケットを使うことで、Excelを一台のコンピュータで、MetaTrader 5を別のコンピュータで実行することもできますし、両方を同じマシン上で動かすこともできます。どのように設定するかはトレーダー自身が決めるべきです。たとえば、MetaTrader 5専用のコンピュータとExcel専用のコンピュータを分けたい場合でも、ソケットを使えば実現できます。また、両方のプログラムを同じマシン上で動かしたい場合でも、通信プロトコルを変更する必要はありません。つまり、ソケットは非常に実用的なツールなのです。

では、具体的にどうやって接続するのでしょうか。これは個人の選択次第です。しかし、今回私たちはPythonをExcelで使う方法を示しており、さらにPythonスクリプトはMetaTrader 5でも利用できることがわかっています。これにより、多くの可能性が開けます。最も基本的な方法は、MetaTrader 5とExcelの両方で使えるPythonサーバーを作ることです。その前に、少し整理して考えてみましょう。Pythonを使えば、スプレッドシートに直接値を書き込んだり読み込んだりできます。しかし、前に説明したように、理想的にはこれをソケット経由でおこなうべきです。クライアントを動かすには、MetaTrader 5かExcelのどちらかが必要になります。もしMetaTrader 5上でサーバーを作る場合、クライアントはExcel側でプログラムすることになります。ただし、MQL5を使えば、EAと直接やり取りできるクライアントを非常に簡単に作ることも可能です。

ここまでで、ある程度プログラミングが必要だということは理解できたと思います。では、まずはシンプルなものから始めましょう。複雑だったり混乱するような要素は不要です。そこで考え出されたのがエコーサーバーのアイデアです。これはExcelとMetaTrader 5の接続をテストするためだけに使います。なぜなら、ソケットプログラミングの最も基本的な形だからです。


エコーサーバーの作成

これは最もシンプルなサーバーコードなので、あまり多くを期待しないでください。目的は、ExcelがPythonで書かれたサーバーとどのように連携するかをテストすることです。まず、Pythonでサーバーコードを作成します。内容は以下の通りです。

01. import socket
02. import xlwings as xw
03. 
04. def Echo():
05.         wb = xw.Book.caller()
06.         server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
07.         server.bind(("127.0.0.1", 27015))
08.         wb.sheets[0]['A1'].value = "Waiting connection..."
09.         server.listen(1)
10.         client, addr = server.accept()
11.         client.send("Wellcome to Server in Python\n\r".encode())
12.         wb.sheets[0]['A2'].value = str(f"Client connected by {addr}")
13.         while True:
14.             info = client.recv(512)
15.             if not info:
16.                 break
17.             client.send(b"Echo Server:" + info)
18.         wb.sheets[0]['A3'].value = "Client disconnected"
19.         client.close()

Pythonスクリプト

「これだけ?」と思われるかもしれません。はい、これだけです。ただし1つだけ補足があります。このコードはExcelと連携し、サーバーで何が起きているかをレポートとして出力することを目的としています。Pythonに慣れている方は、このコードに特に驚くことはないでしょう。しかし、何が起きているのかよくわからない方のために、Pythonスクリプトが実際に何をしているのか順を追って確認してみましょう。

01行目と02行目では、Pythonに必要なモジュールを読み込む指示を出しています。04行目では、後でVBAから呼び出すための手続きを作り始めます。ただし、まずPython内でこの部分を理解しておきます。05行目では、Excelとの接続をおこなっています。08、12、18行目では、実行状況をExcelのシートに書き込んでいます。これは前回のテーマと同じ方法です。

残りの行はすべてエコーサーバーの一部です。重要なポイントとして、このサーバーは同時に1つの接続しか受け付けません。つまり、クライアントが接続すると、サーバーはそのクライアントに専有され、他の接続を受け付けません。クライアントが接続を終了すると、サーバーも停止します。汎用性は高くありませんが、今回はあくまでテスト目的です。

もう1つ重要な点は07行目です。ここで指定されている値に注目してください。このIPv4形式のアドレスは、特定のクライアントからの接続のみを受け付けることを意味します。今回の例ではローカルホストです。つまり、クライアントとサーバーは同じマシン上で動作する必要があります。物理マシンでも仮想マシンでも構いませんが、両方が同じ「船」に乗っていることが重要です。

この値をクライアントが存在する別のアドレスに変更することもできます。ウェブサイトを指定することも可能です。しかし、わからない場合や任意のアドレスからの接続を許可したい場合は、値を「0.0.0.0」に設定します。この場合、Python(正確にはソケット)が任意のクライアントからの接続を受け付けるようになります。ただし、同時に接続できるクライアントは1つだけです。

では、複数のクライアントを同時に扱いたい場合はどうすればよいでしょうか。その場合は、スレッドで接続を処理する必要があります。C++でやったのと同じようなイメージです。ただし、Pythonではこれもより簡単に実装できます。しかし、今回の目的では不要です。サーバーが接続を受け付け、受信したデータをそのまま返すだけで十分です。

Python側のサーバーコードができたら、前回のトピックでやった方法と同じ手順でVBAから起動できます。「つまり、RunPython関数でサーバーを起動するのですね?」はい、その通りです。ただし、前回のVBAコードを少しだけ修正します。VBAコードは次のようになります。

1. Private Sub Worksheet_Activate()
2.     MsgBox "Call Server..."
3.     RunPython "import Server_Echo; Server_Echo.Test()"
4. End Sub

VBAスクリプト

このコードのシンプルさは印象的です。03行目では、呼び出すファイル名と手続き名を変更しただけです。重要なのは02行目です。この行は、サーバーを再度呼び出したときに確認できるようにしています。実際に別のシートに切り替えてサーバーを起動してみましょう。2回目の起動では、Pythonがエラーを表示します。しかし、これは本当のエラーではなく、サーバーがすでに動作しているかどうかをコードがチェックしていないだけです。同じセッションで2つのクライアントが同時に接続しようとしても、同様の挙動になります。これらの実験は宿題として残しておきます。この体験を通して、この教育用コードの制約を理解し、必要な修正が自分でできるようになります。

完成済みの完全なエコーサーバーコードを提供してほしいと思われるかもしれませんが、個人的に、これにはあまり意味がないと思います。自分で問題を見つけ、解決策を考える方が学びが深まるからです。こうして考えながら作ることで、ソケットの仕組みや基本概念がしっかり身につきます。既にヒントは提示済みなので、あとは実際に何が起きているか理解し、問題を修正するだけです。難しくはありません。

これでPythonサーバー部分の準備は完了です。次に、MQL5側のクライアントを見ていきましょう。


MQL5でのクライアント実装:エコーバージョン

サーバー側と同様に、クライアントも完全にPythonで実装することは可能です。しかし今回は、後でおこなう作業に備えて、Pythonの話は一旦置いておき、MQL5に注目します。クライアント側のコードは以下のとおりです。

01. //+------------------------------------------------------------------+
02. #property service
03. #property copyright "Daniel Jose"
04. #property description "Echo Server Test Service."
05. #property description "Requires that the Python server is running in Excel."
06. #property version   "1.00"
07. //+------------------------------------------------------------------+
08. input string     user00 = "127.0.0.1";   //Address
09. input int        user01 = 27015;         //Port
10. //+------------------------------------------------------------------+
11. void OnStart()
12. {
13.     char buff[], resp[];
14.     int sock = SocketCreate(), ret;
15.     uint len;
16.     string szMsg;
17.     
18.     if (sock == INVALID_HANDLE)
19.     {
20.         Print("Unable to create socket. Error: ", GetLastError());
21.         return;
22.     }
23.     if (!SocketConnect(sock, user00, user01, 1000))
24.     {
25.         Print("Connection with the address [", user00, "] in port ", user01, " failed. Error code: ", GetLastError());
26.         SocketClose(sock);
27.         return;
28.     }
29.     while (!_StopFlag)
30.     {
31.         szMsg = TimeToString(TimeLocal(), TIME_DATE | TIME_SECONDS);
32.         len = StringToCharArray(szMsg, buff) - 1;
33.         Print("To Server: ", szMsg);
34.         if (SocketSend(sock, buff, len) != len)
35.         {
36.             Print("Error code: " , GetLastError());
37.             break;
38.         };
39.         szMsg = "";
40.         do
41.         {
42.             len = SocketIsReadable(sock);
43.             ret = SocketRead(sock, resp, len, 1000);
44.             if (ret > 0)
45.                 szMsg += CharArrayToString(resp, 0, ret);
46.         }while ((ret <= 0) && (!_StopFlag));
47.         Print("From Server: ", szMsg);
48.         Sleep(1000);
49.     }
50.     SocketSend(sock, buff, 0);
51.     SocketClose(sock);
52. }
53. //+------------------------------------------------------------------+

MQL5のサービス

このコードについて説明する前に、正常に動作させるための小さな設定について確認しておきましょう。そうです、MetaTrader 5に対してソケットの使用を許可する必要があります。まずは、受信先のアドレスを指定する必要があります。これは次のようにおこないます。

この設定をおこなうことで、MQL5クライアントコードがどのように動作するか確認できるようになります。最初に目に入るのはおそらく02行目でしょう。確かに、Serviceタイプを使ってソケットを実装できます。ソケットを実装できないのはインジケーターだけであり、それ以外のアプリケーションタイプでは自由にソケットを使用できます。

このコードは、前回の記事で見たコードに似ていると思われるかもしれません。その通りです。ソケット向けのコードは基本的にどれも似ています。そのため、これまで説明してきた内容はすべてここでも当てはまります。唯一の実質的な違いは、50行目です。

なぜこの行が必要なのかと、疑問に思われるかもしれません。理解するためには、Pythonサーバーのコードを見直す必要があります。サーバー側の15行目では、サーバーが不正な情報や空の情報を受け取った場合、サーバーが終了します。50行目はまさにこれをおこなうためのコードです。正直なところ、サーバーとクライアントの間で接続終了を通知する最適な方法ではありません。しかし、初歩的な目的や基本的なテストには十分です。そのため、クライアントがサーバーに接続している間、MetaTrader 5上では次のような表示になります。

情報がリアルタイムでエコーされることに注目してください。動作は単純ですが、通信の流れがどのように進むかを理解するのに役立ちます。次にExcelでの表示を見ると、何が起きているのかさらにイメージしやすくなります。


次の段階に進む前に解決すべき問題

さて、ここまでの内容は基礎中の基礎です。しかし、次の段階に進み、完全なコードを確認する前に、もう一度確認しておきたいことがあります。このコードの目的はあくまで教育用であるという点です。今の段階で自分たちがどの位置にいるのか、少し振り返ってみましょう。

経験のある方にとっては、ここまでの内容は特に驚きではないでしょう。しかし、ソケットを使ったことがあまりない方も多いと思います。正直に言うと、学習の初期段階で、手順通りやれば完璧に動くと思われてしまうのが心配です。

現実はそれほど甘くはありません。恐れる必要はありませんが、注意を怠ると問題に直面します。ソケットは、プログラム間の通信、異なるプラットフォーム(すなわち異なるオペレーティングシステム)間、あるいは異なるコンピュータ間でも、要素間のやり取りを簡単にしてくれる、非常に単純な通信ツールです。しかし、必要な注意を怠ると、深刻な問題に遭遇したり、発生した障害を理解して解決するのが難しくなることがあります。

ここで、すでに動作している簡単な実装を振り返ります。この実装では、ExcelとMetaTrader 5の間で情報交換が可能です。以前の記事では、コマンドライン上で単一のサーバーを動かしましたが、今回は通常は想定しない状況を試すことになります。つまり、1つのコンソールでサーバーがすでに起動している状態で、同じOSセッション内の別のコンソールから同じサーバーを起動してみるということです。どうなるか分からなければ試してみてください。結果として、それは不可能であることがわかります。これは、ソケットについて多くの人(経験豊富な人でさえ)が少なくとも理論的にはソケットを完全には理解していないことを示しています。

具体的には、ミニチャットサーバーを1つのコンソールから起動した場合、同じOSセッション内の別のコンソールから同じサーバーを起動することは絶対にできません。これは事実です。

さらに、ミニチャットサーバーはポート27015を使用しています。そして、Excelで動作するエコーサーバーも同じポートを使用します。理論上、ここでリソースの競合が発生します。OSは、同じプロトコルで同じポートを使う別のサーバーの起動を許可しません。今回使用しているのはTCPプロトコルです。ただし、1つのサーバーでTCP、もう1つでUDPを使う場合は、同じポートを使っても問題はありません。

しかし、同じポート、同じプロトコル、同じホストを使用すると、状況は少し複雑になります。

ここで強調したいのは、ソケットを上級者レベルで使おうと考えている人に向けて、ソケットを扱う際にはいくつかの注意が必要であることを理解してほしいという点です。そして、ExcelとMetaTrader 5の通信が実際にどのように実装されるかを見る前に、異なる2つのサーバーが同じリソースを使用した場合に何が起きるかを理解しておいてほしいのです。今回の場合、リソースとは同じプロトコル、同じポート、同じホストを指します。理解するために、まずミニチャットサーバーを起動し、接続待機状態にします。

次に、Excel上でエコーサーバーを起動し、こちらも接続待機状態にします。すると、以下のようになります。

さて、ここでお願いです。テストを始める前に、どちらのサーバーがクライアントからの接続を受け付けるかを考えてみてください。言い換えれば、どちらのサーバーがリッスンを開始し、クライアントの要求に応答するでしょうか。両方のサーバーとも非常にシンプルなコードで動作していることに注意してください。クライアントが正しいサーバーかを確認する処理はありません。クライアントからどの種類のリクエストが来るかをフィルタリングする処理もありません。

私の説明が正確に伝わっているか不安ですが、ポイントは次の通りです。これら2つのサーバーは異なるものですが、同じリソース(同じポート、同じプロトコル(TCP)、同じホスト)を使用しているのです。これが、ソケットを扱う上での難しさの核心です。特定の要件を満たすサーバーが既に存在する状態で、知らないうちに同じリソースを使う別のサーバーを起動すると、クライアントが正しい応答を受け取れなくなる可能性があります。

したがって、ここで示しているコードは完全なものではなく、あくまで個人用・教育用のものだということを理解することが重要です。実務で使われるサーバーコードは、はるかにより厳格なルールに従い、堅牢な設計原則に基づいて作られています。

多くの場合、解決策は簡単だと考える人もいるでしょう。「プロトコルやポートを変更すれば、サーバー間の競合は解消できる」これは確かに正しいです。たとえば、1つのサーバーを1台のマシンに置き、もう1つのサーバーを別のマシンに置くという単純な方法でも、同じポートとプロトコルを使っていたとしても問題は解決できます。

しかし、ここでの疑問は残ります。上の画像では、どちらのコンピュータがクライアントの接続要求に応答するでしょうか。これを理解するには、どのサーバーが最後に起動されたかを知るだけで十分です。つまり、まだクライアントが接続していない場合、最初に接続を試みるクライアントは、最後に起動したサーバーに接続されます。そのサーバーが停止すると、直前に起動したサーバーが新たな接続要求の処理を開始します。

ここで、重要な注意点があります。クライアントがサーバーに接続している状態で、そのサーバーが停止した場合、接続は切断されます。クライアントが自動的に別のサーバーに再接続されることはありません。そういう仕組みではありません。クライアント側から新たに接続要求を送る必要があります。そのときに初めて、停止したサーバーと同じポート、同じプロトコル、同じホストで待機しているサーバーに接続することが可能になります。


まとめ

今回の記事では、ExcelとMetaTrader 5間でメッセージをやり取りする実際の実装はお見せしませんでしたが、私が非常に重要だと考えている点について説明する機会にしたいと思いました。特にソケットに不慣れな方には、ソケットの利用を「世界八番目の不思議」のように過大評価してほしくありませんし、逆に、ソケットが魔法のようにあらゆる問題を解決してくれると期待して失望してほしくもありません。

ソケットは、コンピュータの世界において最も複雑でありながら、同時に最も単純なツールのひとつでもあります。その仕組みを理解していれば、非常に強力な助けとなります。しかし、取るに足らないものだと考え、十分な考察や本質的な理解もないまま「思い通りに使える」と思い込めば、深刻な問題を引き起こしかねません。

このレプリケーション/モデリングサービスについての連載の冒頭では、ソケットを使ってシステム全体を構築することも検討しました。ある意味では、アーキテクチャの観点から見ると、そのほうがむしろ単純だったでしょう。というのも、ティックデータを、MetaTrader 5が実際の取引サーバーへ接続する際に使用するポートへ直接送信すればよいだけだからです。しかし、熟考の末、その案は見送りました。なぜでしょうか。それには、実践的ではあるものの、あまり詳しく解説したくない技術が必要になるからです。ただし、この点については、ぜひ皆さんにも考えてみてほしいと思います。次回の記事では、ExcelがMetaTrader 5にデータを送信し、MetaTrader 5がExcelからのリクエストに応答する仕組みを解説します。

ファイル説明
Experts\Expert Advisor.mq5
Chart TradeとEAの連携を示す(Mouse Studyが必要)
Indicators\Chart Trade.mq5送信する注文を設定するウィンドウを作成する(Mouse Studyが必要)
Indicators\Market Replay.mq5レプリケーション/モデリングサービスと対話するためのコントロールを作成する(Mouse Studyが必要)
Indicators\Mouse Study.mq5グラフィカルコントロールとユーザー間のインタラクションを実現する(リプレイおよび実取引の両方で必須)
Servicios\Market Replay.mq5市場レプリケーション/モデリングサービスサービスを作成および維持する(システム全体のメインファイル)
Код VS C++ Server.cppC++で作成されたソケットサーバーを作成および維持する(ミニチャット版)
Python Server.pyMetaTrader 5とExcel間の通信用のPythonソケットを作成および維持する
ScriptsCheckSocket.mq5外部ソケットとの接続を確認する
Indicators\Mini Chat.mq5ミニチャットをインジケーターとして実装する(サーバーが必要)
Experts\Mini Chat.mq5ミニチャットをEAとして実装する(サーバーが必要)

MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/12744

添付されたファイル |
Anexo.zip (560.03 KB)
初級から中級まで:インジケーター(II) 初級から中級まで:インジケーター(II)
本記事では、移動平均の計算をどのように実装するか、またその計算をおこなう際にどのような点に注意すべきかを確認します。さらに、OnCalculate関数のオーバーロードについても取り上げ、どのバージョンをいつ、どのように扱うべきかを理解していきます。
初級から中級まで:インジケーター(I) 初級から中級まで:インジケーター(I)
本記事では、初めてとなる完全に実用的かつ機能的なインジケーターを作成していきます。目的はアプリケーションの作り方そのものを示すことではありません。皆さんがご自身のアイデアをどのように開発できるのかを理解し、安全でシンプルかつ実践的な方法でそれを適用する機会を提供することにあります。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
初心者からエキスパートへ:市場構造を認識したRSI取引 初心者からエキスパートへ:市場構造を認識したRSI取引
本記事では、相対力指数(RSI)オシレーターを市場構造と組み合わせて取引するための実践的な手法を解説します。特に、チャネル型のプライスアクションパターンに焦点を当て、それらが一般的にどのように取引されているか、そしてMQL5をどのように活用してこのプロセスを強化できるかを説明します。最終的には、トレンド継続の機会をより高い精度と一貫性で捉えることを目的とした、ルールベースの自動チャネル取引システムを構築できるようになるでしょう。