目的
C#とMetaTraderでデータのやり取りをする。
データのやり取りに関する実現方法について
データのやり取りに関する実現方法については,主に3種類あると考えられます。
- 共有メモリを使用する方法
- ソケット通信による方法
- ファイルによる方法
恐らく3番目が一番実装しやすいのではないでしょうか。
ただし,3番目の場合,ファイルアクセスのルールを決めないといけないため,少しコードの工夫が必要です。
本稿では,ソケット通信による実装方法について検討したいと思います。
ソケット通信によるC#とMetaTraderの連携方法について
ソケット通信による方法では,C#に限らすPythonなどでも実装可能なので,少し応用の幅が広いと思います。
データのやり取りに関しては次のように考えます。
C#からの要求に対しては,MetaTraderでは常に決まったポートで待ち受けるようにします。
MetaTraderからの要求に対しても,常に決まったポートで待ち受けるようにします。
これを行うことで,C#からの要求がMetaTraderからの要求とぶつからないようにすることができます。
実装時は,データをやりとりできることをしか検証していないため同じポートでやりました。
コード
C#側
private void connect_ClickAsync(object sender, EventArgs e)//ボタン割り当て
{
ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in ipHostInfo.AddressList)
{
Console.WriteLine(ip.ToString());
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
ipAddress = ip;
//break;
}
}
//ipAddress = ipHostInfo.AddressList[0];
ipAddress = IPAddress.Parse("127.0.0.1");
Task task = Task.Run(async () => { await SocketServer(); });
//接続が成功したら
//disconnect.Enabled = true;
//connect.Enabled = false;
}
public async Task SocketServer()//受信用のサーバを立ち上げる
{
//ここからIPアドレスやポートの設定
// 着信データ用のデータバッファー。
byte[] bytes = new byte[1024];
await Task.Run(() =>
{
try
{
Regex reg = new Regex("\0");
if (server == null)
{
//指定IP 指定ポートでサーバを起動
server = new TcpListener(new IPEndPoint(ipAddress, port));
}
server.Start();
while (startFlg)
{
if (!startFlg)
{
server.Stop();
break;
}
using (TcpClient tcpClient = server.AcceptTcpClient())
using (Stream stream = tcpClient.GetStream())
{
int i = 0;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
string data1 = reg.Replace(Encoding.UTF8.GetString(bytes), "");
// 任意の処理
//データの受取をReceiveで行う。
//int bytesRec = handler.Receive(bytes);
//string data1 = Encoding.UTF8.GetString(bytes, 0, bytesRec);
if (data1.Length > 0)
{
Console.WriteLine("data1の数:" + data1.Length);
Console.WriteLine(data1);
String[] sep = { "," };
String[] sba = data1.Split(sep, StringSplitOptions.RemoveEmptyEntries);
if (this.InvokeRequired)
{
//別スレッドによるUI操作
this.Invoke((MethodInvoker)(() =>
{
bidTbx.Text = sba[1];
askTbx.Text = sba[2];
}));
}
else
{
//UIスレッドからのUI操作
bidTbx.Text = sba[1];
askTbx.Text = sba[2];
}
//大文字に変更
data1 = data1.ToUpper();
//クライアントにSendで返す。
byte[] msg = Encoding.UTF8.GetBytes(data1);
stream.Write(msg, 0, msg.Length);
Array.Clear(bytes, 0, bytes.Length);
}
}
}
// break;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
public static void SocketClient(string st)//クライアント側(C#からMetaTraderにアクセスするとき)
{
//IPアドレスやポートを設定している。
IPHostEntry ipHostInfo1 = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress1 = ipHostInfo1.AddressList[0];
foreach (IPAddress ip in ipHostInfo1.AddressList)
{
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
ipAddress1 = ip;
break;
}
}
ipAddress1 = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress1, 4545);
//ソケットを作成
Socket socket = new Socket(ipAddress1.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
//接続する。失敗するとエラーで落ちる。
socket.Connect(remoteEP);
//Sendで送信している。
byte[] msg = Encoding.UTF8.GetBytes(st + "<EOF>");
socket.Send(msg);
//Receiveで受信している。
byte[] bytes = new byte[1024];
int bytesRec = socket.Receive(bytes);
string data1 = Encoding.UTF8.GetString(bytes, 0, bytesRec);
Console.WriteLine(data1);
//ソケットを終了している。
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
MetaTrader側でどう受け取るかにもよりますが,
SocketClient("buy,141.25,,,OK");
といった具合に要求することを考えています。
MQL4
MQL4側は,ここを参考にしながら実装していければと思います。
完成品
一応置いておきますが,共有メモリでの実装に移行している関係で,正しく動きません!
REFERENCEs
さいごに
投資は自己責任!
カレンダー参加者募集してます!
Have a good MQL Life!!!