サーバータイプのMT4MT5互換コピートレードツール(EA)
公開日:
:
無料配布EA(MT5 用), 無料配布EA(MT4 用), コピートレードツール開発 ea, コピートレードシステム
目次/もくじ
この記事ではWEBサーバーを経由するMT4/MT5のコピートレードシステムの作り方について解説します。EAプログラムからサーバーの構築方法まで説明します。
以前、DLLなしで動くコピートレードシステムを連載しましたが、今回はサーバーを経由するコピートレードシステムを作ります。 以前のコピーツールは、同一PC上で速度を優先したツールなので、業者間アービトラージやストップ狩り返しなどに特化しています。
これから作るツールは、PCから一度サーバーにトレードデータを飛ばし、別のPCでトレードをコピーできるように作ります。
用途としては、
・PCやサーバーを超えてトレードをコピーしたいとき(EAのライセンス料を2つ以上払いたくない?)
・シグナル配信(ソーシャルトレード?・疑似MAM/PAMM?)
に向いています。もちろんDLL・インクルードファイル・ライブラリなどは使用せず、EA単体で稼働するように作ります。
サーバーを経由する分、オフラインでのコピートレードツールよりも反映が遅くなるので、ただ単にPC上でコピーしたい場合は通常版のコピートレードツールの方が向いています。
WEBを経由するコピートレードツール ダウンロード
※2024/1/25
・配信EAの通貨ペア6文字縛りを削除(nikkei,jp225などもコピーできますがその代わり受信側で取引対象外の場合エラーがずっと出ます)
・受信側が日本円口座のときにコピーされなくなるバグを修正
・受信側でUSDT、UST口座に対応
・気配値表示していない通貨ペアが取引されない仕様を修正
・MT5のヘッジ口座で裁量反対売買決済したときに反対注文が新規注文として配信されるバグを修正
WEBを経由するコピートレードツール 使い方
URLの許可(送信EA・受信EA共通)
このコピートレードツールはDLLを使用しない代わりにWebRequestをEA内で使用します。そのため、エキスパートアドバイザの設定でアクセスするURLを許可する必要があります。
「http://mt4-copier.com」
と入力してください。「https」ではなく「http」です。(httpsだとポートが干渉しあって機能しないことがあります)
受信EA、配信EAどちらも共通でこの設定を行う必要があります。
配信EAの設定
任意の通貨ペアチャートにEAを1つセットするだけです。一つのチャートにセットすればすべての通貨ペアを自動的に取得し、送信・受信を行います。時間枠も何でも大丈夫です。
EAのパラメータは実質ありません。
CalcInterval_in_milisecond: EAがサーバーとやり取りをする時間間隔。3000=3秒ごとにサーバーと通信。1秒未満にはできないように制限をつけています。
受信EAの設定
- ProvidersAccountNumber: プロバイダーというのはシグナルプロバイダーのことで、配信者口座の口座番号をここに入力することでシグナルの受信が可能です。
- LotByEquityRatio: trueの場合、ロットは自動算出されます。※1
- FixedLot: 0以上の値の場合、配信者のロットを完全に無視して固定ロットでコピーします。LotByEquityRatioがtrueでも、こちらが0以上の場合はこちらが優先されます。
- CalcInterval_in_milisecond: サーバーと通信をする時間間隔です。3000=3秒ごとにサーバーと通信をします。1秒未満にはできないように制限をつけています。
※「配信者の口座番号が知られてしまえば不正にシグナルが受信できてしまうのではないか」という疑問があるかもしれません。以前は配信者側でパスワードを設定して、それを受信側で入力しないとシグナルを受信できない仕様でした。しかし、シグナル情報が洩れる工程を考慮すると、偶発的に流出するというよりは、一部の心無い受信者がEAと配信者情報とパスワードをセットで流出させてしまう、という確率が非常に高いです。その場合、パスワードを設けてもあまり意味がなく、サーバー側で受信者を管理できていれば、パスワードの必要はないという結論に達しました。
ネットを経由するコピートレードツールの仕様
・サンプルとして開発したものなのでレンタルサーバーの一部を間借りして稼働させています。(オーダーの反映を意図的に遅くしています。)
※1 受信者EAのトレードロットは配信者の証拠金とロットから自動算出されます。(レバレッジに関係なく、証拠金に対するロットの比率がそのまま反映されます。
例:配信者が10万円で0.1ロットのポジションをとった場合、受信者の口座が1万円なら0.01ロットのポジションが自動的にオーダーされます。) 算出されたロットが受信者口座のFX会社の最小ロット未満の場合は最小ロットで取引を行います。MQL5シグナルと同じ仕様です。
・配信者のMT4/MT5ではエキスパート/自動売買が許可されていなくても、サーバーとの通信を行います。(コピートレードの稼働に影響ありません。) 受信者のMT4/MT5ではエキスパート/自動売買が許可されている必要があります。
・配信口座で発生した指値注文、逆指値注文、SLTPはEAによるトレード、裁量によるトレードに関わらず、すべて受信口座に反映されます。
・為替、仮想通貨のコピーが可能です。一方、銘柄名が6文字でないシンボルは業者によって名称が大きく異なるため、取引が反映されません。(株価指数、商品先物、goldなど)サーバーには履歴上のデータだけが残ります。
・受信口座では受信EAをセットした状態で、他のトレードEA、裁量トレードを行うことが可能です。
・受信口座でシグナル受信したオーダーやポジションを削除、決済した場合、再び反映はされません。
・配信者の口座で約定したポジションを何らかの理由で受信口座が即座に受信・トレードできる状態になかった場合、配信者口座で約定から10分経過するまでは受信者側でオーダーを反映しますが、10分以上経過したオーダーは反映されません。ただし、予約注文で未約定の場合は10分以上経過しても反映されます。
・MT5はヘッジモードのみ対応です。(現在、ほとんどのMT5アカウントはヘッジアカウントですが、ごく稀にネッティングアカウントのMT5のFX業者があります。)
・MT5独自のストップリミット注文(ストップ価格に価格が推移した後にリミットを出す注文)は予約注文としては反映されず、約定後に反映されます。通常のストップ注文(逆指値)、リミット注文(指値)は問題ありません。
・最終利用日時から6か月間経過したアカウントは自動的に削除されます。
・決済済み、かつ、登録から1か月以上経過したオーダーはサーバーから情報が削除されます。
コピートレードツール管理画面
開発者と管理者が同一の場合はサーバー上にGUIを作る必要はないのですが、そうでない場合には管理画面があると便利です。そういった需要があることは容易に推察されたので、サーバー上にGUI管理画面を作成しました。シグナルを配信、受信するだけの場合はEAだけあれば十分です。
シグナル受信口座の管理では、サーバー側から利用停止/利用開始させることができます。
もちろん、管理画面を覗くにはログインが必要な仕様にしています。
追記:開発当初は、FX業者を超えたサーバータイプのコピートレードシステムはほとんどありませんでしたが、現在ではわざわざ自分で作らなくてもそういったサービスがあるので、そちらを利用するのが手っ取り早いです。
CopyTradePro | MT4とMT5でコピートレード | 自動売買システム製作工房 (fxfx.work)
(問い合わせ時は紹介欄に「とある技術者の金融工学」)
MQL&WEBサーバーに特有の問題
さて、 サーバーを経由させる場合、これまでにないような問題に直面することがあります。
サーバーがMT4/MT5のアクセスをDos攻撃と勘違いする可能性
サーバーが高頻度のティック更新によるWEBアクセスをDosと勘違いしてしまい、アクセス拒否になることがあります。これはWEBアクセスの頻度を下げるか、サーバーを自分で構築して、 同一IPからの大量アクセスをOKにするか、複数のプロキシを経由するしかありません。ただし、通信プロトコルがHTTPの場合、そもそもウェブページを表示させる段階で大量の送信を行っているので、実はそこまで気にする必要はないのではないかと思います。
ただし、配信口座・受信口座が海外ロケーションのVPS上にある場合、海外IPからのアクセスをはじくように初期設定しているサーバー会社多いので、それはOFFにしておく必要があります。
大量アクセスとサーバーダウンの可能性
ユーザーが増えるとサーバーがダウンする可能性があります。強固なサーバーを使うしかないですね。ただ、PHPの処理自体はシンプルなので、仮想通貨の自動売買のようにパンクするということはなく、比較的耐えると思います。
これまで100アカウント越えのシステムも見てきましたが、サーバー負荷によるダウンは一度も観測していません。
これだけ問題もありますが、 恩恵は余りあるくらい大きいので、十分やってみる価値はあると保証できます。
コピーツールの場合、実質MAMでもEAとして日本国内で販売できる
日本国内で金商法関連法に引っ掛かるケースとしては、
- クローズドな会員制で入手するタイプの投資情報など
- 継続的な支払い等が発生するツール
などがあります。
特にシグナル配信やMAM/PAMMだと国内では問題がありますが、 誰でも入手可能な状態でEAとして売り切りで販売すれば問題はないので、そういったところもクリアできます。(目をつけられたらどうとでもされるでしょうけど)
これは、「アカウント認証をWEBで行うEA」と「サーバーからトレード情報を取得するEA」の見かけ上の区別を受信者側からできないように開発することが可能である、というところがポイントです。
WEBコピートレードツール開発目的
意図としては、
- EAを配布・販売したいけどデコンパイルや流出が心配なとき、
- 擬似的にPAMM,MAMをやりたいとき(ファンドをやりたいけど法的な制限がある場合)
- 利用者をサーバー側から管理したいとき
などを想定しています。 今回はサーバー構築は省き、レンタルサーバーでできるように実装します。
コピートレードの大まかな流れはこんな感じです。
すごいトレーダー(もしくはEA)のトレード
↓
サーバーにそのトレード情報を送る
↓
一般トレーダーがサーバーからその情報を取得し、トレードをコピーする
ゴゴジャン、MQL5などがやっている”シグナル配信”と基本的には同じです。ただし、今回はDLLなしでコーディングします。
必要な言語は、MQLとPHP(ちょっとSQL,HTML)です。データベースを使うので、今回に限ってはPHPがベストだと思います。 汎用性を必要としない開発であればデータベースを使わずにPHP、あるいはPerlやJavaで書いてもOKです。ただし、安いサーバーの場合、昨今はPerlをインストールしていないことが多いので、管理者権限がないサーバーの場合は大人しくPHPにしておいた方が良いと思います。
また、実際にトレードをコピーすると数秒の誤差が生まれるので、 高速スキャルピングのコピーはできません。
サーバー経由のコピートレードができるようになると、いろいろとビジネスの可能性が広がるので、FX業界で動いている方には役に立つと思います。
必要なものは、
- サーバー&データベース
- トレードを送信するEA
- トレードを受信するEA
です。
それぞれ独自に開発する必要があります。
EAを作れる人はそこそこいますが、WEB(データベース)とEAどちらも作れる人はあまりいないので、この際できるようになるとお得かもしれません。
WEBを経由するコピートレードシステムの開発
トレードデータをサーバーに送信する配信EAを作る(MQL)
まず、データをサーバーに送信するEAを作ります。
飛ばすトレード情報のデータは、
- チケットナンバー
- 通貨ペア名
- エントリーの向き
です。他にも情報を追加したい場合は、適宜追加してください。 基本的には上記だけでも何とかなります。
他に入れたい場合は、 ・注文時間 ・注文ロット ・SL ・TP ・注文方式 とかを入れると予約注文や部分決済などにも対応したシステムが作れます。
POSTとGET
これらの情報を何かしらの方法でサーバーに送らなければいけないのですが、MQLのWebRequest関数で送信できるWEBの通信には大きくPOSTとGETがあります。
GETの方が簡単なのでデータ量が短い場合はGETでも大丈夫ですが、ポジションの量が増えたりするとものすごい長いURLになってしまうので、POSTで実装します。
オーダーデータの整形
データの整形ですが、ポジションの数に応じてこの情報を連結させます。
例えば、 123456:USDJPY:BUY@123457:EURUSD:SELL@111111:EURJPY:BUY このような感じです。
それぞれの記号はデータを区切る意味しかないので、 カンマでもコロンでもなんでもOKです。(ただし、データベースが誤認識しやすい記号があるので、それらは避けましょう) Jsonの扱いに慣れている場合はJson形式で書いても良いと思います。XML形式はデータ量がいたずらに増加するのでオススメしません。
今回はMQL4ではなく、MQL5で書いていますが、 基本的にはMQL4と同じです。 オーダー関数が構造体になるくらいの違いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
string TradingData() { string PreTradingData = ""; ulong PositionTicket = 0; string PositionSymbol = ""; int PositionType = -1; for(i=0;i<PositionsTotal();i++) { PositionTicket = PositionGetTicket(i); //--- return order ticket by its position in the list if(PositionTicket>0) { PositionSelectByTicket(PositionTicket); PositionType=PositionGetInteger(POSITION_TYPE); PositionSymbol=StringSubstr(PositionGetString(POSITION_SYMBOL),0); PreTradingData += PositionTicket+":"+PositionSymbol+":"+PositionType+"@"; } } return(PreTradingData); } |
関数化するとこんな感じです。
FX業者によって異なる通貨ペア名の統一
FX業者によっては、USDJPYmとかUSDJPY_xとか銘柄名に余計な文字列がついていることがあるので、 最初の6文字だけを取得するように一般化してください。
StringSubstrを使えば最初の6文字だけを切り取れます。 また、このEAにトレードをさせるわけではないので、for文の判定はPositionsTotal()そのままでOKです。
(以前EA開発講座でやりましたが、for文の中で決済処理をしてしまうとPositionsTotal()の数が変わってしまうことがあるのを回避する話です。)
アカウント情報をサーバーに送る
トレードを送信する側のアカウント情報を サーバーに送る準備をします。トレード情報を送る機能 と アカウント情報を送る機能 を分けて処理します。
「口座の管理や認証処理はとりあえずいらないよ」っていう人はスルーしても大丈夫です。 サーバーに送る情報は、
- サーバーにアクセスする際のパスワード
- 使っている業者
- アカウント名
- アカウント番号
- メールアドレス(パラメタ入力)
- デモ口座かどうか
- 受信者用のパスワード(パラメタ入力)
です。
必要に応じて適宜増やしたり減らしてください。
1 2 3 4 5 6 7 8 9 |
string Data = "postpasskey="+"パスワード" +"&type="+type +"&accountcompany="+AccountInfoString(ACCOUNT_COMPANY) +"&accountname="+AccountInfoString(ACCOUNT_NAME) +"&accountnumber="+AccountInfoInteger(ACCOUNT_LOGIN) +"&email="+YourEmailAddress +"&isdemo="+IntegerToString(IsDemo) +"&enduserpassword="+EnduserPassword +"&dummy=none"; |
この二つの情報(アカウント情報とトレード情報)をサーバーに送信します。
トレード情報は頻繁にサーバーに送信する必要がありますが、アカウント情報はたまに送信すればOKです。 セキュリティ向上のため、SSL接続でPOSTでHTTPリクエストを行います。
ポート制限がかかっているVPS上でMT4を稼働させている場合、SSL接続だとうまく通信できない事例があるので、生HTTPが良いと思います。 平文でGETリクエストでも大丈夫だとは思いますが、一応暗号化はしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void SendPOST(string URL, string str) { int WebR; int timeout = 5000; string cookie = NULL,headers; char post[],ReceivedData[]; StringToCharArray( str, post ); WebR = WebRequest( "POST", URL, cookie, NULL, timeout, post, 0, ReceivedData, headers ); if(!WebR) Print("Web request failed"); Comment(CharArrayToString(ReceivedData)); } |
この関数は指定したURLに対して、指定した文字列をPOSTで送る関数です。このURLはあとでサーバーを構築した際に指定します。
中で何をしているかわからなくてもこの関数をコピペすれば大丈夫です。 ちなみに、MQLのWebRequestは少しクセがあり、リファレンスのサンプルも上手く動かないので、少し注意が必要です。
サーバー側のプログラミング(PHP)
サーバー側では、大きく分けて4つのプログラムと2つのデータベースが必要です。
- EAから送信されたアカウントデータを受け取るプログラム
- EAから送信されたトレードデータを受け取るプログラム
- EAに送信するアカウントデータ(許可・不許可)を送るプログラム
- EAに送信するトレードデータを送るプログラム
と
- アカウント情報を記録するデータベース(テーブル)
- トレードデータを記録するデータベース(テーブル)
注:MT4/MT5からのアクセスにはセッション/クッキーが使えない
MetaTraderはブラウザではないので、MT4/MT5からのWEBアクセスはセッションもクッキーも使えません。 つまり「前回のアクセスから何秒以内は処理しない」といった処理はPHP側ではできないので、 データベースで処理するか、MQL側で処理させなければいけません。
EAから送信されたアカウントデータを受け取るプログラム
アカウント名や会社名に含まれている記号を除去する
FX業者によっては会社名などに;や,などが入っているため、サーバープログラムでそれが原因のバグが発生する可能性があります。(お前のことだFXTF) まずはそれを取り除く関数を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function fixaccountname() { global $accountname; if( strpos($accountname,':') !== false ) $accountname = str_replace(":","",$accountname); if( strpos($accountname,';') !== false ) $accountname = str_replace(";","",$accountname); if( strpos($accountname,'?') !== false ) $accountname = str_replace("?","",$accountname); if( strpos($accountname,'_') !== false ) $accountname = str_replace("_","",$accountname); if( strpos($accountname,'.') !== false ) $accountname = str_replace(".","",$accountname); if( strpos($accountname,',') !== false ) $accountname = str_replace(",","",$accountname); if( strpos($accountname,'(') !== false ) $accountname = str_replace("(","",$accountname); if( strpos($accountname,')') !== false ) $accountname = str_replace(")","",$accountname); if( strpos($accountname,'+') !== false ) $accountname = str_replace("+","",$accountname); if( strpos($accountname,' ') !== false ) $accountname = str_replace(" ","",$accountname); } function fixaccountcomopany() { if( strpos($accountcompany,':') !== false ) $accountcompany = str_replace(":","",$accountcompany); if( strpos($accountcompany,';') !== false ) $accountcompany = str_replace(";","",$accountcompany); if( strpos($accountcompany,'?') !== false ) $accountcompany = str_replace("?","",$accountcompany); if( strpos($accountcompany,'_') !== false ) $accountcompany = str_replace("_","",$accountcompany); if( strpos($accountcompany,'.') !== false ) $accountcompany = str_replace(".","",$accountcompany); if( strpos($accountcompany,',') !== false ) $accountcompany = str_replace(",","",$accountcompany); if( strpos($accountcompany,'+') !== false ) $accountcompany = str_replace("+","",$accountcompany); } |
変数を引数ではなくグローバル変数で使っていますが、引数にした方がポピュラーかもしれません。
EAからのPOSTデータを受け取る
まずは、トレードを送信する親側の処理を行うPHPファイルを作ります。これは一般的なホームページの問い合わせフォームやログインの処理と同じです。POSTで送られてきたデータを連想配列$_POST[‘変数名’]で受け取れます。
それぞれの情報はPOSTで送られてくるので、一般的なフォームと同じようにそれらを受け取ります。
ハッカーがスクリプトを仕込んでPOSTしてくると簡単にSQLインジェクションできてしまうので、htmlspecialchars()やstripslashes()で一応平文に直します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php //POSTデータがあればそれぞれ受け取る isset($_POST['accountname']) ? $accountname = $_POST['accountname'] : $accountname = NULL; fixaccountname(); isset($_POST['accountcompany']) ? $accountcompany = $_POST['accountcompany'] : $accountcompany = NULL; //FXTFには全角文字が含まれているので取り除く if( $accountcompany == "FXTradeFinancialCoLtd" ) $accountname = substr($accountname,0,8); fixaccountcomopany(); isset($_POST['serialid']) ? $serialid = $_POST['serialid'] : $serialid = NULL; isset($_POST['email']) ? $email = $_POST['email'] : $email = NULL; isset($_POST['accountnumber']) ? $accountnumber = $_POST['accountnumber'] : $accountnumber = NULL; isset($_POST['accountequity']) ? $accountequity = $_POST['accountequity'] : $accountequity = NULL; isset($_POST['isdemo']) ? $isdemo = $_POST['isdemo'] : $isdemo = NULL; isset($_POST['accountcurrency']) ? $accountcurrency = $_POST['accountcurrency'] : $accountcurrency = NULL; ?> |
後はこれを、新規ユーザーの場合と既存ユーザーの場合に分けてデータベースに入れるだけです。
1 2 3 4 5 6 7 8 9 |
<?php //ユーザーがすでに登録されているかどうか調べる $searched = mysql_query("SELECT * FROM `traders` WHERE `accountnumber`= '$accountnumber' AND `accountname` = '$accountname'"); //ユーザーがデータベースに既に登録されている場合 if( $trader = mysql_fetch_array($searched) ) { .... ?> |
データベースについて 初めての受信の場合初回の場合はHOSTテーブルにINSERTします。
1 2 3 4 5 |
<?php $insert_query = "INSERT INTO `HOST` (`accountcompany`,`accountname`,`accountnumber`,`isdemo`,`email`,`enduserpassword`,`created_at`,`last_time`) VALUES ('$accountcompany','$accountname','$accountnumber','$isdemo','$email','$enduserpassword','$time','$time')"; ?> |
データベースに挿入している記述ですが、あらかじめ適当なデータベースとテーブルを作成し、データベースにアクセスしておく必要があります。
分からない方は、ここら辺の知識はここで説明するには少し冗長になってしまうので、「php sql データベース接続」、「データベース 作り方」などで調べてみてください。
この処理をした際に管理者のメールアドレスに通知するなどの処理を書いても良いと思います。
データベース 二回目以降の受信の場合
二回目以降の場合は、アカウント情報はUPDATEするだけです。
1 2 3 4 |
<?php $update_query = "UPDATE `HOST` SET `last_time` = '$time' WHERE `accountnumber` ='$accountnumber'"; $issue_query = mysql_query($update_query); ?> |
以上がアカウント情報の処理です。
EAから送信されたトレードデータを受け取るプログラム
こちらもPOSTでEAからデータを受け取る処理は一緒です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php isset($_POST['orderticket'.$i]) ? $orderticket[$i] = $_POST['orderticket'.$i] : $orderticket[$i] = NULL; isset($_POST['ordersymbol'.$i]) ? $ordersymbol[$i] = $_POST['ordersymbol'.$i] : $ordersymbol[$i] = NULL; isset($_POST['ordertype'.$i]) ? $ordertype[$i] = $_POST['ordertype'.$i] : $ordertype[$i] = NULL; isset($_POST['orderlots'.$i]) ? $orderlots[$i] = $_POST['orderlots'.$i] : $orderlots[$i] = NULL; isset($_POST['orderopenprice'.$i]) ? $orderopenprice[$i] = $_POST['orderopenprice'.$i] : $orderopenprice[$i] = NULL; isset($_POST['orderopentime'.$i]) ? $orderopentime[$i] = $_POST['orderopentime'.$i] : $orderopentime[$i] = NULL; isset($_POST['ordercloseprice'.$i]) ? $ordercloseprice[$i] = $_POST['ordercloseprice'.$i] : $ordercloseprice[$i] = NULL; isset($_POST['orderclosetime'.$i]) ? $orderclosetime[$i] = $_POST['orderclosetime'.$i] : $orderclosetime[$i] = NULL; isset($_POST['orderstoploss'.$i]) ? $orderstoploss[$i] = $_POST['orderstoploss'.$i] : $orderstoploss[$i] = NULL; isset($_POST['ordertakeprofit'.$i]) ? $ordertakeprofit[$i] = $_POST['ordertakeprofit'.$i] : $ordertakeprofit[$i] = NULL; isset($_POST['ordermagicnumber'.$i])? $ordermagicnumber[$i] = $_POST['ordermagicnumber'.$i] : $ordermagicnumber[$i] = NULL; ?> |
あとはそのオーダーがリアルタイムのオーダーかそれともヒストリーのオーダーか、 また、新規登録されるオーダーかすでにデータベースに登録されているオーダーかで場合分けして処理すればOKです。
1 2 3 4 5 6 7 8 9 10 |
<?php //イメージ //すでにそのオーダーが登録されているかどうか調べる $searched2 = mysql_query("SELECT * FROM `positions` WHERE `orderownerid` ='$serialid' AND `orderticket` = '$orderticket[$i]' "); //登録されている場合 if( $existorder = mysql_fetch_array($searched2) ) { .... ?> |
EAに送信するトレードデータを送るプログラム
こちらも同様で、echoなどで簡単な文字列を出力すればWebRequestを通じてEAにデータが渡ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php ...... //指定されたアカウントの最新300オーダーを調べる $searched = mysql_query("SELECT * FROM `order_data` WHERE `orderownerid` ='$serialid' ORDER BY registereddate DESC LIMIT 300"); while( $order = mysql_fetch_array($searched) ) { $searched2 = mysql_query("SELECT * FROM `CopiedAccount` WHERE `serialid` = '$serialid'"); $host = mysql_fetch_array($searched2); $orderdata = $order['orderticket']. "+".$time. "+".$order['ordersymbol']. "+".$order['ismarketorder']. "+".$order['ordertype']. "+".$order['orderlots']. "+".$order['orderopenprice']. "+".$order['positionopentime']. "+".$order['orderstoploss']. "+".$order['ordertakeprofit']. "+".$order['orderclosetime']. "+".$host['accountequity']. "+".$host['accountcurrency']. "@"; $output .= $orderdata; } echo $output; .... ?> |
あとは、送られてきたオーダー情報が「初めて受信したもの」か「前にも受信したことがあるデータ」なのかでSQLに対するクエリを変えればOKです。
基本的には、まずは初めてのセットか2回目以降かで分けます。 初めての場合はSQLにINSERTする必要があるので、
1 2 3 |
$insert_query = "INSERT INTO `USER` (`hostnumber`,`accountcompany`,`accountname`,`accountnumber`,`accountequity`,`accountcurrency`,`isdemo`,`email`,`created_at`,`last_time`) VALUES ('$hostnumber','$accountcompany','$accountname','$accountnumber','$accountequity','$accountcurrency','$isdemo','$email','$time','$time')"; |
アカウントの情報をUSERテーブルに入れます。 2回目以降の場合はUPDATEするだけです。 テーブルの列にRunとかAuthとかの名前の列を作っておき、 そこが1の場合はトレードを許可し、 0の場合はトレードをさせないようにします。
1 2 3 4 5 6 7 8 9 10 11 |
$user_query = "SELECT * FROM `USER` WHERE `accountnumber`='$accountnumber'"; $user_array = mysql_query($user_query); if( $user = mysql_fetch_array($user_array) ) { //check the auth if( $user['run'] != 1 ) { echo "---Not allowed---"; } } |
これでサーバー側でユーザーの管理ができるようになります。
1 2 3 4 5 6 7 8 |
$host_query = "SELECT * FROM `HOST` WHERE `accountnumber` = '$hostnumber'"; $host_array = mysql_query($host_query); //already exited HOST trader if( $host_data = mysql_fetch_array($host_array) ) { echo strip_tags($host_data['tradingdata']); } |
受信する側は、親アカウントのアカウント番号と親が設定したパスワードがあれば、 トレードをコピーすることができます。
php.iniの設定を変える
1 |
max_input_vars = 10000 |
トレード情報を大量にPOSTするのでデフォルトの上限ではいっぱいいっぱいになる可能性があります。そのため、php.iniの設定で、一度にPOSTを処理できる上限を上げておく必要があります。
CRONと定期処理
受信者が増えた場合やコピーを長期間行っている場合、データベースに情報が溜まり続けてしまいます。昨今のデータベースは数万件程度は軽々処理しますが、それでもデータベースの単調増加する肥満にはダイエットが必要です。
具体的には、古いオーダーは定期的に処理するスクリプトを用意しておき、週末などにCRONで処理させましょう。
CRONとは定期的な処理を可能にするためだけの機能で、最近のサーバーには付属しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php require("database.php"); //登録日が古い順に100件取り出す $searched = $dbh->query("SELECT * FROM `positions` ORDER BY `positions`.`RegisteredDate` ASC LIMIT 100"); //ポジション情報を取得 while($position = $searched->fetch_assoc()) { //すでに決済しているか調べる if( $position['OrderCloseTime'] == 0 ) continue; //未決済の場合はスルー else//決済している場合 { //登録から1か月以上経過している場合 if( date('Y/m/d H:i:s') > $position['RegisteredDate'] + 60*60*24*31 ) { //そのオーダー情報を削除 $ProvidersAccountNumber = $position['ProvidersAccountNumber']; $OrderTicket = $position['OrderTicket']; $dbh->query("DELETE FROM `positions` WHERE `ProvidersAccountNumber` = $ProvidersAccountNumber AND `OrderTicket` = $OrderTicket"); } } } ?> |
CRONがないサーバーの場合でも、他のサーバーから処理させることは可能です。(CRONはローカルファイルである必要がない)
トレードデータをサーバーから受信する受信EA(MQL)
次はトレードを受信する方のEAを作ります。 トレードデータを送信するEAと比較すると、トレード関数を実装しなければいけないので、少し厄介です。
まずトレードデータをサーバーから取得する関数を作ります。まだサーバー側を作っていないので詳しくは言及できませんが、データを送る側のEAが送ったものと似たようなものを似たような形式で受信すると考えておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
string GetTradingData(string URL, string str) { int WebR; int timeout = 5000; string cookie = NULL,headers; char post[],ReceivedData[]; StringToCharArray( str, post ); WebR = WebRequest( "POST", URL, cookie, NULL, timeout, post, 0, ReceivedData, headers ); if(!WebR) Print("Web request failed"); string TradingData = CharArrayToString(ReceivedData); if( StringFind(TradingData,"---getting tradingdata failed---",0) != -1 ) { Print(TradingData); } return(TradingData); } |
関数名にGetが入っていますが、リクエストはPOSTです。 ここらへんのURLとかデータベースとかは後で扱うので、今は外枠だけ作っておけばOKです。 取得したデータは最初配列になっているので、CharArrayToStringで文字列に直す必要があります。
受信データをポジションを反転する(MQL5の場合)
次に、 サーバーから取得したトレードポジションを現在持っているかどうかを判定する関数を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//そのオーダーをすでに保有しているかどうか調べる----------------- bool CheckHaveThisOrderNow(int CheckMagic) { bool ThisPositionHaveNow = false; string CheckMagicStr = IntegerToString(CheckMagic); for(j=0;j<OrdersTotal();j++) { R = OrderSelect(j,SELECT_BY_POS,MODE_TRADES); //このオーダーを持っている場合 //if( StringFind(IntegerToString(OrderMagicNumber()),CheckMagicStr,0) > -1 ) if( IntegerToString(OrderMagicNumber()) == CheckMagicStr ) { ThisPositionHaveNow = true; break; } } return(ThisPositionHaveNow); } |
後で詳しく扱うのですが、 オーダーを送信をする際にマジックナンバーに親のトレードのチケットナンバーを差し込み、 ポジションのマジックにそのチケットナンバーのものがあるかないかで判定を行います。オーダーコメントでも同様の処理が可能ですが、FX業者によってはオーダーコメントを勝手に上書きしたり、書き足したりする仕様の業者があるので、オーダーマジックナンバーにしました。
何を言っているかというと、受信側のEAではサーバーから受け取った情報と現在持っているポジションを照らし合わせる必要があります。
しかし、同じ通貨ペアで同じ方向に複数のポジションがあった場合にそれをどうやって区別するのか、という問題があります。
これで親のトレードと同じポジションを今現在持っているかが判定できます。持っていなかったらエントリーし、持っていたらスルーします。
受信データのオーダーを過去に持っていたかどうか調べる
次に、 同じように”過去に”親のトレードを保有し、決済したかどうかを判定する関数を作ります。
これは何のためにやるかというと、何らかのエラーによりポジションが決済された際に、再エントリーするのを防ぐ役割があります。
もしくは、親トレーダーがエントリーして、そのトレードをコピーしたは良いけど、気に食わないから手動で決済する、という要望に応えることもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//過去にこのポジションを持っていたかどうか調べる bool CheckHadThisOrderPast(int TheMagic) { bool HadThisPosition = false; string TheMagicStr = IntegerToString(TheMagic); for(j=OrdersHistoryTotal()-1;j>=MathMax(OrdersHistoryTotal()-MaxOrdersHistoryTotal,0);j--) { R = OrderSelect(j,SELECT_BY_POS,MODE_HISTORY); //if( StringFind(IntegerToString(OrderMagicNumber()),TheMagicStr,0) > -1 ) if( IntegerToString(OrderMagicNumber()) == TheMagicStr ) { HadThisPosition = true; break; } } return( HadThisPosition ); } |
基本的には先ほどと同じ構造の関数です。サーバーから受け取ったオーダーのチケットナンバーと現在持っているポジションのマジックナンバーを比較します。
関連記事
-
ハイリスクハイリターンEA (MT4)[一発逆転EA]
バックテスト結果 EURUSD 2019/1/1~2019/12/31 H1 スプレッド:
-
日足MACDロジックEA高スプレッド対応 (MT4)
バックテスト結果 ご覧の通り、固定ロットできれいなグラフを出せています。ただ、取引回数が少ない
-
一発逆転EA(MT4)無料EAダウンロード
マーチンゲールはハイリスクなシステムと分かっていても甘い蜜のような誘惑が人を惹きつけますね。 結局
-
機械学習EA(スタンドアロン型)[MT5]
学習型のシステムって大抵は外部ソフト(RとかMatLabとか)を使って、その結果をEAに渡す、みたい
-
標準偏差とマーチンゲール [システムトレード検証](MT5)
標準偏差っていうのは統計で使われるやつで、ボリンジャーバンドの中身でもあります。それだけで優位性があ
コメント
いつも良質な記事をありがとうございます。
サーバー経由のコピートレードができるようになると、いろいろとビジネスの可能性が広がるので、FX業界で動いている方には役に立つと思います。
>コピートレードシステムの構築のご依頼は可能でしょうか?
一度、メールにてご連絡を頂けますと幸いです。
開発をお願いしたい案件があるのですが
メールが送れないのですが、どうすれば良いでしょうか?