全体のタスクFXの注意すべき仕様ストップレベルによるバグの回避コピー元のプログラムを作るファイル関数の使い方コピー先:受信側のコードを書くStringReplaceとその使い方ポジションを照らし合わせるオーダーの反映の状態は二つオーダーの状態とパターンを調べる決済する必要がある場合の決済処理for文の中でOrderCloseを使うべきではないオーダーコメントはFX業者に勝手に書き換えられるバグ取りと改良より高速にコピーさせるリバーストレードできるようにするコピートレードツールの特徴MT4で自動売買ソフトを稼働させるトレーダーには、ときたまトレードを別のMT4にコピーしたい場合があります。デモ口座でしか稼働しないトライアル版のEAや、口座番号に制限がかかっているEA、FX業者に制約があるEAなどです。今回は同一コンピューター上でのコピートレードシステムを作ります。コピートレードツールにはサーバーを経由するタイプのものとサーバーを経由しないタイプがありますが、今回はサーバーを経由しないシンプルなタイプです。ネットを経由させないコピーツールとしてのメリットは、トレードの反映のスピードが早いこと、外部サーバーの構築、管理をする手間がないことが挙げられます。逆にデメリットとしては、”コピー元のMT4とコピー先のMT4が同一のPC上になければならない”という点があります。この使用場面はいろいろと限られてくると思いますが、基本的には個人利用を想定しています。仕様は下記のとおりです。・DLL、外部ソフトは必要なし・WEBサーバーを経由しないコピーツール(同一コンピューター上に複数のコピー元とコピー先のMT4がなければならない)・コピー元、コピー先に同じEAを一つずつセット(パラメータでコピー元なのか、コピー先なのか指定)↑普通だったらコピー元とコピー先のEAを分けるところなんでしょうけど、管理・編集がめんどいってことで合体させました。・コピーするかどうかのタイミングはレート更新ベース(レート更新が遅い時間帯・通貨ペアにEAをセットするとコピーが遅くなる)・シンボル名が6文字でないGold,Silver,Oil,DAU,SP500,Coffeeなどはコピーできない.左が配信元(コピー元)、右が受信先(コピー先)受信側のFX業者のレート更新が遅いので、反映に多少ラグが生じています。配信元のMT4にセットする場合trueにします。受信(コピー先)のMT4にセットする場合trueにします。受信(コピー先)のMT4にセットする場合、親のアカウント番号を入力します。受信(コピー先)のMT4にセットする場合、コピーするトレードのロットを入力します。受信(コピー先)のMT4にセットする場合のトレードのスリッページです。予約注文には対応していません。※このEAを使って発生した損失などは一切責任を負いません。ダウンロード下記はこのEAのダウンロードリンクです。EA無料使い放題企画をしています。EAのパスコードは企画参加者に配布しています。詳しくはこちら汎用版MT4/MT5コピートレードツールこのページはあくまでMT4間のコピートレードツールの開発に焦点を当てたページになります。コピートレード総合はこちら。無料ダウンロード開発概要さて、実際の仕様の話ですが、2010年代初頭であれば外部ソフトやDLLの開発が必要でしたが、現在のMT4であればDLLや外部ソフトを使わずに、EA単体で稼働させることが可能です。(もちろんプログラマの腕ありきですが・・・)これを実現させる肝となるのが、ファイル関数のCOMMON機能です。ファイル関数は、EA上のデータをMT4外のファイルに記録することができます。MT4のターミナル上にデータを保存するグローバル変数はそれぞれのMT4上に記録されますが、ファイル関数でCOMMON指定することで、より上位のディレクトリにデータを保存することが可能です。それにより、異なるFX業者のMT4同士でデータのやりとりが可能になります。ちなみに、データ格納のアクセス範囲としては、ファイル関数(COMMON指定)>ファイル関数(通常)>グローバル変数(外域変数)>PUBLIC変数>ローカル変数といった感じです。右に行くほどデータにアクセスする範囲が狭くなり、外側から参照・書き込みできなくなります。逆に、左になればなるほど、長期の間データを保存できます。頻繁に出し入れするデータはなるべく短期型の格納方式を使ってメモリの消費を減らしましょう。MQLを長年いじったことがある方でもファイル関数を触る機会というのは、そう多くはないと思います。・コピートレード・アービトラージ・外部ソフトを使った分析(Rとか)に限られてくるので、一般的な自動売買ソフトを開発しているだけではお目にかかることはないでしょう。全体のタスク全体的にやるべきタスクは下記になります。■コピー元(配信側)・オーダーをファイル関数でファイルに記録する■コピー先(受信側)・ファイル関数でトレードデータを引っ張ってくる・引っ張て来たデータを現在のポジション情報と照らし合わせる・照らし合わせた内容に従ってエントリーor決済するFXの注意すべき仕様コピーツールを作る前に、MT4の仕様上の話をしなくてはなりません。複数のMT4業者を利用したことがある方はご存じかと思いますが、業者によって通貨ペアの名称が若干違います。ある業者ではUSDJPY、ある業者ではUSDJPYm、またある業者はusdjpyだったり...大文字小文字が異なっていたり、通貨ペアの後(サフィックス)に変な記号を勝手につけられることがあります。これをちゃんと処理しないとバグに繋がります。トレードデータを送信する際にはこれらの邪魔な記号を消して、6文字に統一すると処理が楽になります。これは、文字列関数を使えば一発です。StringSubstr(Symbol(),6);StringSubstrは指定文字列の指定番号以降の文字列を抽出することができるので、適当にsymbolSuffixなどの変数を文字列型で宣言して、横に置いておきましょう。外して統一し、オーダーを出す際には再び必要になります。(あとでくっつけます)ストップレベルによるバグの回避またFX業者によって仕様が異なるものとして、ストップレベルがあります。ストップレベルとは、予約注文を出す際に最も近くに出せるレートの幅のことです。業者としては予約注文(リミットオーダー、ストップオーダー)は、現在レートからある程度離れたところに置いてほしいわけですが、その最小許容幅がストップレベルです。今回はレートの厳密性よりも、スピードを重視したコピートレードシステムを開発したいので、すべて成行注文でオーダーします。(トレードをコピーする側のMT4の話)もちろん、コピー元のトレードは成行以外で自由にやっていただいてOKです。スリッページもあまり狭くすると、リクオートが多発してエントリーしなくなるので、なるべくデフォルトは広めにしましょう。為替と仮想通貨以外のシンボル(ゴールド、インデックス、米、石油など)は、FX業者によってシンボル名が全然違ったり、そもそもチャートがないこともあるので、今回は為替と仮想通貨だけを考えます。コピー元のプログラムを作るまずは、コピー元のプログラムを作ります。トレードを受信する側と比較するとかなり簡単です。コピー先に送る情報として最低限必要なのは、通貨ペア、売り買いの方向、オーダーを識別するためのチケットナンバーです。この三つがあれば、とりあえずコピーは可能です。ファイル関数は文字列型でしか格納できないので、これらを一つの情報にまとめます。チケット番号:通貨ペア(6文字):売買@で一つのオーダーの情報にします。情報を区切る記号(:@)はなんでもOKですが、業者がシンボル名に絶対に使用しない記号にしましょう。WEB系の言語やAPIを触ったことがある方ならJSON形式の方が分かりやすい方もいるかもしれません。(ただし、MQL4/MQL5にJSONをエンコード、デコードする関数はありません。)オーダーが複数になった場合には、チケット番号:通貨ペア(6文字):売買@チケット番号:通貨ペア(6文字):売買@...という風にどんどん連結していきます。OrderTicket()+":"+PositionSymbol+":"+OrderType()+"@";}}return(PreTradingData);}あとはこの関数が吐き出すトレード情報の文字列をファイル関数でファイルに書き込みます。ファイル名はなんでもOKです。ここではCoypingTradingData.txtとしています。ファイル名に変な記号(カンマなど)を入れると、OSが変な拡張子として認識したりするので、特殊記号はいれないでください。ファイル関数の使い方ファイル関数は通常の変数などと違って、”○○という名前のファイルを(書き込み専用or読み込み専用)開きます”と宣言します。FileCloseという手順を踏まなければなりません。JavaやPHPなど他の高級言語を触ったことがある場合はそれほど違和感はないと思います。){FileWriteString(FileHandle,TradingData());FileClose(FileHandle);}ファイル関数はMT4ターミナルの外部フォルダにアクセスするので、PCの状態によってはアクセスに失敗することがあります。(メモリがいっぱいとか、ビジー状態とか)そのため、成功するまで最大10回繰り返す仕様にしています。コピー元がファイルに書き込みをするタイミングと受信側ファイルを読み込むタイミングが重なると、Windowsの仕様上例外処理が必要になります。(対象のファイルに対して読み込みと書き込みを同時に行うことはできない。)【追記】ここの処理は後の記事でwhile文からfor文に書き換えています。あとスリープも入れています。FILE_SHARE_READという指定もあるのですが、これは機能していないので、通常版で記述しています。ここで宣言していない変数は、あとでコードをまとめたときに別の場所で宣言しているので、コピペする際には全体のコードから取得してください。ここで一番重要なのはファイル関数を使う際にFILE_COMMONを指定することです。これを入れることでフォルダアクセスが一つ上層になり、ほかのMT4からもアクセス可能な領域にデータが保存されます。この保存場所は「C:UsersAppDataRoamingMetaQuotesTerminalCommonFiles」です。このディレクトリの書き込み権限がない場合はエラーになりますので、書き込み権限を与えておいてください。(デフォルトでは通常書き込みOKになっているはずです。)コピー先:受信側のコードを書くコピー先(受信側)のコードに入ります。コピー先でまずやらなくてはならないことは、ファイル関数でファイルからトレード情報を引っ張ってくることです。"FAIL";return(FileData);}【追記】while文をfor文に直しています。(OnTimerでもOKです。)FILE_READを使えば、ファイルの情報を取得することができます。ここらへんはヘルプでもフォーラムでも載っているので、詳しくはそちらを見てください。この関数が吐き出す情報は、チケット番号:通貨ペア(6文字):売買方向@...となっているので、この情報を扱いやすいように分割しなければなりません。文字列関数を使ってそれぞれ分割した文字列を変数に入れます。OrderData[i];StringReplace(OrderData_ticket[i],":","");StringReplace(OrderData_symbol[i],":","");StringReplace(OrderData_type[i],"@","");.....MQL4はMQL5と違って構造体は使えないので、OrderData_ticketのような変数名で代用しています。【追記】バージョンアップでMQL4でも構造体が使えるようになりました。for文の100というのは「配信元が100以上のポジションを同時に保有しないという前提の数字」です。文字列の検索が終わり次第、breakするので、実際に100回計算することはないと思います。StringReplaceとその使い方StringReplace関数は、特定の文字列の検索文字列を別の文字列に置き換えます。“かいうえお”となるように、一部だけを置換することができます。ここら辺はコードを読んで理解するよりも自分で考えた方が早いと思います。要するに、1124310:USDJPY:0@1123311:EURUSD:0@1123412:GBPUSD:0@1123413:AUDJPY:0@1123414:CADJPY:0@1123415:USDJPY:1@...のような形でデータが並んでいるので、それぞれデータごとに変数に格納できればOKです。これでざっくり、コピーするべきトレードの情報が取得できたので、次は「そのトレード情報を現在のトレード状態と照らし合わせる」箇所に入ります。ポジションを照らし合わせる取得したコピー元のトレード情報を、現在のトレード状態と照らし合わせる作業をします。容易に想定されるバグとして、何度も同じポジションを取ったり決済したりを繰り返す、というものがあります。これを解消するには、コピー先のオーダーの履歴に、すでにそのオーダーを取得したことがあるかどうかを調べる作業が必要です。オーダーをコーディングしていませんが、受信側がオーダーをコピーしてポジションを取得する際に、そのオーダーのコメントに親のオーダーのチケット番号を入れます。配信側が持っているオーダーのチケット番号が一致していれば、それはコピートレードで対応されたオーダーということになります。受信側のオーダーのマジックナンバーに配信側のチケット番号を入れています。MQL4ではOrderSelectの際にMODE_HISOTRYを選択すると、決済済み、削除済みのオーダーを参照できます。参照できる決済済み削除済みのオーダーは、MT4で表示されている履歴に依存するので、表示されている履歴が短い場合は、その分しか参照できません。逆に全履歴がターミナル上で表示されている場合には、全履歴を取得することができます。(今後のアップデートで変わるかもしれませんね。)今回のコピートレードでは、コピーしたオーダーのコメントに、コピー元のチケット番号を入れる仕様にしました。これによって、そのオーダーを過去にコピーしたことがあるのかどうかがわかります。ちなみにMT5のネッティングアカウントの場合、オーダーコメントは比較的変わってしまうので、この手法は使えません。オーダーの反映の状態は二つまた、履歴上のオーダーの検索と同時に、コピーするべきトレードが現在コピーされているかどうかを検索する必要があります。A・今、コピーするべきオーダーを持っているか調べるB・過去にコピーするべきオーダーを持っていたか調べるつまりこの2パターンです。何を想定しているかというと、せっかくコピーしたトレードを裁量で決済されてしまったパターンです。この場合、もう一度ポジションを保有するか、それとも、トレーダーを信用してポジションを見送るか、の選択になるのですが、せっかくトレーダーが何かの意図をもって決済したものを、間髪入れずに再ポジションしたら、クレームになりそうな気がします。(もちろん誤って決済してしまった、という可能性もあると思います。)しかし、過去のトレードも参照しておけばバグの可能性も減らせることができるので、今回は「コピーしたポジションをトレーダーが裁量で決済した場合、再エントリーしない」仕様にします。先ほどと同じように、今度は”現在もっているポジション”とコピー元のトレード情報を照らし合わせます。true;break;}}return(ThisPositionHaveNow);}ちょっとややこしいかもしれませんが、やっていることは、A・今、コピーするべきオーダーを持っているか調べるB・過去にコピーするべきオーダーを持っていたか調べることが必要で、そのための独自関数を作っただけです。これまでで「”過去に”コピー元のトレードを持っていたか調べる関数」と「”現在”コピー元のトレードを持っているか調べる関数」を作りました。次はまず、それぞれのオーダー情報に対して、2つの関数を適応した際の組み合わせ4パターンを考えます。オーダーの状態とパターンを調べる[]パターン1履歴にコピー元のトレードを持っていて、今は持っていない→一度コピーはしたが裁量で決済された→何もしない[]パターン2履歴にコピー元のトレードを持っていて、今も持っている→ありえないパターン。(バグってる)→何もしない[]パターン3履歴にコピー元のトレードがなく、今もない→直ちにエントリー[]パターン4履歴にコピー元のトレーがないが、今現在持っている→現在配信元がポジションを持っている→何もしないこうしてみると、実際にエントリー処理するべきなのはパターン3だけです。・受信側であるポジションを持っている&&ファイル関数のデータにそのポジションに対応するオーダーがない場合に決済します。前回までで買い=0、売り=1としたのは、OP_BUY==0であり、OP_SELL==1であるためです。買い=1、売り=-1の方が直観的ではありますが、0,1にすることによってそのままOrderSendが使えます。){OrderSending(OrderData_ticket[i],OrderData_symbol[i],OrderData_type[i]);}前回までで買い=0、売り=1としたのは、OP_BUY==0であり、OP_SELL==1であるためです。買い=1、売り=-1の方が直観的ではありますが、0,1にすることによってそのままOrderSendが使えます。case.}OrderSendはOnTicke(Start)内にべた書きでもいいですが、一応関数化して使いましょう。ファイル関数から取得したトレード情報は文字列型なので、オーダー関数を使うには必要に応じて型を変換する必要があることに注意してください。ファイル関数の通貨ペアは6文字ですが、実際にこれからエントリーしようとする通貨ペアはFX業者によって6文字ではないかもしれません。USDJPY-m)通貨ペアの文字列は完璧に一致していないと、オーダーがはじかれるため、あらかじめ保存したExを使い、文字列を連結しています。決済は「ファイル関数から取得した文字列に既定のトレード情報がなくなったら」決済とします。勘の良い方はお気づきだと思いますが、これ、比較的危ういです。いうのもファイル関数がファイルの取得に失敗した場合、返り値が””になって、全決済してしまう可能性があるからです。)これを回避するにはファイル関数の参照エラーをきっちり分けてやればOKです。パターン1:ファイル関数が正常に作動し、トレード情報がまだある状態パターン2:ファイル関数が正常に作動し、トレード情報が消えた状態(決済)パターン3:ファイル関数が失敗した場合(エラー)パターン2とパターン3をちゃんと区別して書けば、万事OKです。rejected");}for文の中でOrderCloseを使うべきではない話が少しそれますが、多くのプログラマやEA開発代行業者が決済の際にfor文とOrdersTotal()を併用しています。これはちょっとあやういです。いうのも、OrdersTotal()は現在保持しているオーダーの総数です。そのfor文の中でオーダーを決済してしまえば、処理の途中でOrdersTotalの数が変わってしまいます。for文が本来回るはずだった回数が減っていき、ポジションの番号の順番も変わる可能性があります。今のところはたまたま、RefreshRate()するかOnTickから一度抜け出すまではOrdersTotalに入っている値が変わらないという芳しくない”仕様”がこのバグの防波堤になっていますが、将来的にこの”仕様”が改良される可能性はかなり高いです。そのため、決済するべきオーダーのチケット番号は一度なにがしかの変数で保管して、for文を抜けた後に決済処理した方が安全です。オーダーコメントはFX業者に勝手に書き換えられる話を戻します。注意するべきは、業者によってオーダーコメントに変な文字列が追加されるケースがあることです。業者側が勝手に”at12345678tp”のようないらない文字列を付け足すことがあります。(タイミングはまちまちです。)そのため、if(オーダーコメント==調べるチケット番号)としてしまうと、正常に処理されない可能性があります。ここはStringFindを使って、オーダーコメントの中に指定のチケット番号が”含まれているかどうか”を使いましょう。検索文字列が見つかった場合、その文字列の位置を返すので、0以上の場合は合致ということになります。最後まで合致しなければコピー元がポジションを決済したということになり、オーダーを決済します。【追記】FX業者によっては決済後のオーダーコメントを”tp”だけにしたりする場合があるので、オーダーコメントではなくマジックナンバーに親のチケット番号を入れる仕様に変更しました。これでコピーツールの全体が終わりました。次回は全体のコードとそれぞれのケースについて考察します。・予約注文もコピーする・SL,TPもコピーする・配信元のロット比率も反映できるようにする・コピーしようとしたタイミングで配信元が約定してから○○分以上経っているポジションはコピーしないなどの追加機能を付けても良いと思います。前回までに書いたコードでは、ごくまれに受信側が勝手にオーダーを決済してしまうというバグがありました。これはファイルにアクセスする際に書き込みと読み込みがまったく同じタイミングで行われることで、読み込み結果が空白となり、それをEAが”ポジションなし”と判断していただめです。解決策1:書き込み、読み込みするファイルを複数に分けて、読み込み結果が同じ時だけ処理する↑コーディングがめんどい、泥沼になるような気がする...解決策2:書き込み、読み込みのタイミングをずらすために、ローカルタイムの秒数の剰余で実行をずらすとか↑コピー処理が早いことが唯一のメリットなのに、それが失われると作る意味がない...しかし、とりあえず「ポジションがない状態」と「読み込みに失敗した状態」を区別して、ファイルにアクセスできない場合にはSleepを入れてちょっと待つ仕様にしたところ、問題は解決しました。FileReadString(FileHandle);FileClose(FileHandle);break;}}return(FileData);}(これは以前while文で書いていた、ファイルのトレードデータを読み込む関数です)より高速にコピーさせるまた、やっぱりコピーの反映が遅いのが気になります。EAをセットしている通貨ペアチャートだけが低速で、他のチャートが頻繁に動いているとき、コピーの反映が遅いというのはやっぱり良くないと思います。他のパターンとしても、コピーする通貨ペアが頻繁に動いていて、セットしている通貨ペアが鈍い可能性も考えられます。そこで、OnTickの中に再帰的なループを入れました。While文で延々とループするとメモリを圧迫したり、フリーズしたりする可能性があるのですが、妥協案として、100回ループしてOnTickで再読み込みという手を取りました。OnTick(){//---for(l=0;l&lt;100;l++){Sleep(100);RefreshRates();....下記はその結果です。前よりも反映速度が格段に上がっています。(ごく稀に遅くなる可能性は内包していますけどね。)リバーストレードできるようにするつづいてはリバーストレードができるように改良します。端的に言うと、コピー元と逆向きのポジションをコピーできるようにするということです。MarketInfo(TheSymbol+Ex,MODE_ASK);}}ちょっとわかりにくいかもしれませんが、左はFXPROのデモ口座で右はXMのデモ口座です。左でトレードを行うと右で逆向きのトレードをすぐさま入れています。ようにすればOKです。役に立ったと言っています。AMスキャルピングでも早くコピートレードできるソフトを探してます。PMダウンロードして使わせてもらいます。親のアカウント番号とは口座番号でしょうか?メールの場所がわからずこちらに質問しました。PM変則的な決済に対応できますでしょうか?例えば、2万通貨のポジションがあり、決済は1万通貨で2回に渡る場合です。受信(コピー先)のMT4にセット>する場合、コピーするトレードのロットを入力します。ロットを親と同じにする方法はありすますか?よろしくお願いいたします。お世話になります、野田と申します。私事ですが結構長くFXをやっているのですがなかなか勝てずいろいろなスクールやら詐欺商材にひっかかったりして結局私では勝てないというのが結論です。それで自分で勝てないならEAに稼いでもらおうと考えました。それでEAの勉強を始めようと本を買ってはみたのですが勉強ぎらいで3日坊主の性格でさっぱり進みません。それでも1つだけどうしても試してみたい勝てそうなロジックがあるのですが自分では作れないのでプロの方にお願いしようと思ってEA制作の方のページを見ていてこちらのページにたどり着きました。EA制作をお願いするにはこの方しかないと確信してこのメッセージを書いています。先生のお時間に余裕のある時で構いませんのでEAを作っていただけないでしょうか。FXでさんざん負けてしまってあまりお金に余裕がないので高額だとすぐにはお願いできません。ロジックはそれほど複雑なものではないのですがもしEAを作っていただけるとしたらおいくらぐらいなのでしょうか。お返事いただけましたら幸いです。PM有効なEAだと思います。