どうも潤奈です( ・Д・)
今回が最終章です!頑張りましょう!
では参考コードEAを元に解説して行きたいと思います!
え?それどこにあるの?という方は次の記事から読み進めて下さい。
潤奈流EA講座①(参考コードと構成説明)
それ以降の記事はこちら。
潤奈流EA講座②(プロパティとパラメーター)
潤奈流EA講座③(OnInit,OnTick,OnDeinit関数)
潤奈流EA講座④(オリジナル関数とは,AdjustPoint関数,AdjustSlippage関数)
潤奈流EA講座⑤(Position関数,OpenOrder関数,CloseOrder関数)
TrailingStop関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//トレーリングストップ void TrailingStop(){ double TSP; int res=0; for(int i=OrdersTotal()-1;i>=0;i--){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true){ if(OrderSymbol()==_Symbol && OrderMagicNumber()==MagicNumber){ if(OrderType()==OP_BUY){ TSP=Ask-TrailingPips*Pips; if(OrderOpenPrice()<TSP && OrderStopLoss()<TSP){ res=OrderModify(OrderTicket(),OrderOpenPrice(),TSP,0,0,clrYellow); } }else if(OrderType()==OP_SELL){ TSP=Bid+TrailingPips*Pips; if(OrderOpenPrice()>TSP && OrderStopLoss()>TSP){ res=OrderModify(OrderTicket(),OrderOpenPrice(),TSP,0,0,clrYellow); } } } } } } |
これはエントリー後に価格の動きに合わせて損切値を変更させる関数になります。
それでは分解して行きましょう。
1 2 3 4 |
//トレーリングストップ void TrailingStop(){ } |
トレーリングストップは戻り値を必要しないので、void型でTrailingStop関数を宣言します。
1 2 |
double TSP; int res=0; |
次に、トレーリングストップを設定する値を入れる箱としてdouble型のTSP変数を用意し、注文を変更した際に返る戻り値を入れる箱としてres変数を用意します。
1 2 3 |
for(int i=OrdersTotal()-1;i>=0;i--){ } |
for文を使用して保有ポジションをチェックして行きます。
おさらいですが、for(変数宣言と初期値;繰り返す処理数の範囲;処理カウント){ }になります。
今回の処理内容は、注文合計数から1引いた数からスタートして、0になるまで1を引きながらその回数分処理をします。
1 2 3 |
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true){ } |
前記事にも同じ内容が出ていますが、OrderSelect関数を使用してそのポジションの情報を取得します。
この文では「〇〇ポジションさん。前に出て来て下さ~い!」という段階です。
1 2 3 |
if(OrderSymbol()==_Symbol && OrderMagicNumber()==MagicNumber){ } |
次にその呼び出したポジションが現在と同じ通貨ペア出身なのか、現在と同じマジックナンバーを持っているかを確認します。
1 2 3 4 5 6 |
if(OrderType()==OP_BUY){ 買いポジションの処理 }else if(OrderType()==OP_SELL){ 売りポジションの処理 } |
最後に買いポジションですか?売りポジションですか?を確認して、対象の処理へ進みます。
1 2 3 4 5 6 7 8 9 10 11 |
買いポジションの場合 TSP=Ask-TrailingPips*Pips; if(OrderOpenPrice()<TSP && OrderStopLoss()<TSP){ res=OrderModify(OrderTicket(),OrderOpenPrice(),TSP,0,0,clrYellow); } 売りポジションの場合 TSP=Bid+TrailingPips*Pips; if(OrderOpenPrice()>TSP && OrderStopLoss()>TSP){ res=OrderModify(OrderTicket(),OrderOpenPrice(),TSP,0,0,clrYellow); } |
まず買いポジションの場合はTSP変数にAsk値からトレーリングストップのpips引いた数値を代入し、売りポジションの場合はBid値に足した数値を代入します。
最終確認で、2つ条件を確認します。(例:買いポジション)
①OrderOpenPrice関数で注文時の価格を取得し、TSP値が注文時価格より大きいかを確認します。
これが何故必要か分かりますか?
実はこれがないとエントリーした瞬間にトレーリングストップが発動してしまいます。
例えば、注文時に損切値を30pips下に設定し、トレーリングストップは10pipsに設定したとしましょう。この設定で①の条件がある場合と、ない場合では発動タイミングに大きな差が生まれます。
【①の条件がある場合】
現在値より10pips下の価格が、注文時の価格より大きい。が条件ですので、トレーリングストップが発動するのは、注文時の価格より10pips上に値が上がった時に現在値から10pips下に損切値が設置されます。それまでは注文時の価格より30pips下に損切値が設定されたままです。
【①の条件がない場合】
この条件がない場合は、注文後すぐにでも現在値の10pips下に損切値が設置されてしまいます。せっかく注文時に30pips下に損切値を指定していてもこれでは意味がなくなります。
②OrderStopLoss関数で損切値を取得し、TSP値が現在の損切値より大きいかを確認します。
この①と②の条件がどちらも満たしている時に、OrderModify関数で注文内容に変更を加えます。
OrderModify関数の引数は、OrderModify(チケット番号、注文時価格、損切価格、利確価格、有効期限、色)を指定してあげます。
ちなみに今回のトレーリングストップでは利益は出来るだけ伸ばせるようにと、発動時に利確価格を0にしていますが、「損切価格は切り上げたいけど利確価格は継続させたい!」であれば、利確価格の所へOrderTakeProfit()という関数を入力しておけばそのポジションの利確価格を取得し再設定するので利確価格は継続されます。
PerfectOrder関数
1 2 3 4 5 6 7 8 9 10 11 12 |
//パーフェクトオーダーエントリー int PerfectOrder(){ int entry=0; double MA1=iMA(_Symbol,0,Period1,0,MODE_SMA,PRICE_CLOSE,1); double MA2=iMA(_Symbol,0,Period2,0,MODE_SMA,PRICE_CLOSE,1); double MA3=iMA(_Symbol,0,Period3,0,MODE_SMA,PRICE_CLOSE,1); if(MA3<MA2 && MA2<MA1)entry=1; if(MA3>MA2 && MA2>MA1)entry=-1; return(entry); } |
これは3本の移動平均線の値を取得し、その並びが期間順にパーフェクトオーダーになったらエントリー指示となる1か-1を返すオリジナル関数になります。
1 2 3 4 |
//パーフェクトオーダーエントリー int PerfectOrder(){ } |
まずint型のPerfectOrder関数を宣言します。
1 |
int entry=0; |
次にint型のentry変数に0を代入してリセットしておきます。
1 2 3 |
double MA1=iMA(_Symbol,0,Period1,0,MODE_SMA,PRICE_CLOSE,1); double MA2=iMA(_Symbol,0,Period2,0,MODE_SMA,PRICE_CLOSE,1); double MA3=iMA(_Symbol,0,Period3,0,MODE_SMA,PRICE_CLOSE,1); |
移動平均線の価格を入れる箱をdouble型でMA1,MA2,MA3と宣言します。
その箱の中に代入する形で、移動平均線を求めるiMA関数を書いて行きます。
iMA関数の引数は、iMA(通貨ペア、時間軸、期間、シフト、平均化メソッド、適用価格、シフト)です。
iMA関数の引数について簡単に説明すると、
通貨ペア:_Symbolは現在の通貨ペアを指定します。
時間軸:0は現在の時間軸を指定します。
期間:移動平均を求める期間で、パラメーターで設定した値を使用します。
シフト:求めた移動平均線を前後に指定本数分ずらして表示します。
平均化メソッド:計算方式を指定します。
適用価格:始値~終値のどの価格で計算するか指定します。
シフト:何本目の足の移動平均線値を取得するか指定します。
まとめると、MA1変数の場合。現在適用している通貨ペアの時間足で、期間5の単純移動平均SMAで計算し、計算する値は終値を使用。ローソク足1本前の計算値を代入する。となります。
1 2 |
if(MA3<MA2 && MA2<MA1)entry=1; if(MA3>MA2 && MA2>MA1)entry=-1; |
次はエントリー条件を作成します。
パーフェクトオーダーが条件ですので、移動平均線の並びが買いの場合は長期<中期<短期、売りの場合は長期>中期>短期である必要がありますね。
ではその条件をif文で作成しましょう。
まず注意点としては、3つ以上の条件を符号で比べる事は出来ません。
例えばif(MA3<MA2<MA1)とは使用出来ませんので注意して下さい。
ですので、買いでは長期<中期であるか確認し、中期<短期であるかも確認する工程が必要になります。
それを式にすると、if(MA3<MA2 && MA2<MA1)となり複数の条件を指定する時は&&で繋げます。
この条件に満たされる場合はentry変数に1を代入、逆に売りのパーフェクトオーダーの条件が満たされる場合はentry変数に-1を代入するようになります。
どちらも条件を満たさない場合は、entry変数は0のままになります。
1 |
return(entry); |
最後にreturn関数でentry変数の値を戻り値として、OnTick関数下にあるint Entry=PerfectOrder();のPerfectOrder関数に値を戻してEntry変数に代入してエントリー判断に使用します。
PerfectClose関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//パーフェクトオーダークローズ int PerfectClose(int Position){ int close=0; double MA1=iMA(_Symbol,0,Period1,0,MODE_SMA,PRICE_CLOSE,1); double MA2=iMA(_Symbol,0,Period2,0,MODE_SMA,PRICE_CLOSE,1); double MA3=iMA(_Symbol,0,Period3,0,MODE_SMA,PRICE_CLOSE,1); if(Position==1){ if(MA3>MA2 || MA2>MA1)close=1; }else if(Position==-1){ if(MA3<MA2 || MA2<MA1)close=-1; } return(close); } |
これは3本の移動平均線の値を取得し、ポジションを持っている場合その期間毎の並びがパーフェクトオーダーではない場合、クローズ指示となる1か-1を返すオリジナル関数になります。
1 2 3 4 |
//パーフェクトオーダークローズ int PerfectClose(int Position){ } |
まずint型のPerfectClose関数とPerfectClose(関数内で使用する型と引数(変数))を宣言します。
1と-1を入れる箱として、int型のPosition変数を用意しました。
1 |
int close=0; |
次にint型のclose変数に0を代入してリセットしておきます。
1 2 3 |
double MA1=iMA(_Symbol,0,Period1,0,MODE_SMA,PRICE_CLOSE,1); double MA2=iMA(_Symbol,0,Period2,0,MODE_SMA,PRICE_CLOSE,1); double MA3=iMA(_Symbol,0,Period3,0,MODE_SMA,PRICE_CLOSE,1); |
ここは先ほどのPerfectOrder関数と同じですので内容は省略します。
1 2 3 4 5 6 |
if(Position==1){ 買いパーフェクトオーダーのチェック指示の場合 }else if(Position==-1){ 売りパーフェクトオーダーのチェック指示の場合 } |
PerfectClose関数ではPosition変数に引数として1と-1を渡しています。
これは買いと売りのどちらのパーフェクトオーダーの条件が崩れているかの確認をする為に使用しています。
買いか売りかの条件を確認し、対象の処理へ進みます。
1 2 3 4 5 |
買いパーフェクトオーダーのチェック指示の場合 if(MA3>MA2 || MA2>MA1)close=1; 売りパーフェクトオーダーのチェック指示の場合 if(MA3<MA2 || MA2<MA1)close=-1; |
買いのパーフェクトオーダーでは長期>中期 か 中期>短期かのどちらかの条件が満たされればパーフェクトオーダーではないという事になりますので、close変数に1を代入します。
どちらかの条件が満たされているかを確認する場合は || で繋げます。
売りの条件も符号だけ変更し、パーフェクトオーダーではない条件を満たしていればclose変数に-1を代入します。
どちらも条件を満たさない場合は、close変数は0のままになります。
1 |
return(close); |
最後にreturn関数でclose変数の値を戻り値として、OnTick関数下にあるPerfectClose関数に値を戻して手仕舞い条件の確認に使用します。
まとめ
ここまでご覧いただきありがとうございました。
出来るだけシンプルに見やすいプログラムのEAを意識して作成しましたので、これでもまだまだ未完成な部分ではあります。
例えば、TrailingStop関数はOnTick関数の直下にある為、価格受信の度に計算されます。
そこまで頻繁に計算する必要はないですよね?とか
PerfectOrder関数はパーフェクトオーダーになったタイミングを判断している訳ではなく、今の段階でパーフェクトオーダーになっているかの確認をしているだけですので、「ポジションを持っていない時はエントリーしない」という条件を外せば価格受信する度にエントリー指示を満たしてしまいます。
複数ポジションを持たせようとするEAにする場合はそのまま使用出来ませんので注意が必要です。
しかし、これは基本的な組み合わせの型(ベース)にはなると思いますし、カスタマイズがし易いのではないかと思います。
今後はカスタマイズしやすい部品をブログで紹介していけたらと思っています。
私も日々勉強していく中でプログラムの書き方が変化するかもしれませんが、皆さんと共に成長出来たらと思っています。
では( ・Д・)
コメント