トップ  >  自作してみる >  EA作成の応用  >  ea3.EAの実装
スポンサーリンク
検索

↑の検索エンジンが表示されない人は、
↓の古い検索エンジンを使用して下さい。
カスタム検索
MQL4リファレンスツリー
ea3.EAの実装



注意事項:
このページにあるサンプルソースは、実際に売買を行う処理が含まれているので、絶対にライブ口座では実行しないで下さい。 念の為、デモ口座でしか処理しない対策処理を施しています。
これはあくまで勉強用のソースコードです。

仕様の再確認

前回決めた仕様です。 これを見ながらEAを実装していきましょう。
懸案 仕様
エントリー基準 ○短期単純移動平均と長期単純移動平均がクロスした時にエントリーする
○逆にクロスしたらクローズする。
○短期SMA期間は5日、長期SMAは25日で固定
トレードスタイル ○順張りのみ
リミット・ストップ ○リミットは20%に設定
○ストップは10%に設定
○エントリー直後に入れる必要は無い
○トレーリングストップはしない
判定タイミング ○エントリー・クローズ判定はローソク足確定時に行う
○リミット・ストップは指定時間経過毎に行う
建玉と増玉 ○増玉はしない
○ロットは最小ロット固定

EAの基礎作成(セーフティ)

EAを早く作成したいと思うかもしれませんが、まずは基礎を作成しましょう。
まずはEA作成の基本で説明したデモ口座チェックのセーフティを追加します。
うっかりライブ口座で動作させてしまった時にEAをアンロードさせる処理です。

ソースコード:
//+------------------------------------------------------------------+
//| OnInit(初期化)イベント
//+------------------------------------------------------------------+
int OnInit()
{
    if ( IsDemo() == false ) {            // デモ口座以外の場合
        Print("デモ口座でのみ動作します");
        return INIT_FAILED;                            // 処理終了
    }

    return( INIT_SUCCEEDED );      // 戻り値:初期化成功
}


EAの基礎作成(処理タイミング)

仕様の判定タイミングに、ローソク足確定時と指定時間経過毎があるので、
処理タイミングを分ける処理を追加します。

まずはローソク足確定時にだけ処理する関数を作成します。

ソースコード:
//+------------------------------------------------------------------+
//| ローソク足確定時の処理
//+------------------------------------------------------------------+
void TaskPeriod() {
    static    datetime s_lasttime;                      // 最後に記録した時間軸時間
                                                        // staticはこの関数が終了してもデータは保持される

    datetime temptime    = iTime( Symbol(), Period() ,0 );  // 現在の時間軸の時間取得

    if ( temptime == s_lasttime ) {                     // 時間に変化が無い場合
        return;                                         // 処理終了
    }
    s_lasttime = temptime;                              // 最後に記録した時間軸時間を保存

    // ----- 処理はこれ以降に追加 -----------

    printf( "[%d]ローソク足確定%s" , __LINE__ , TimeToStr( Time[0] ) );
}


やっている内容はO1.オブジェクト系インジケータ作成(NYクローズライン[1点タイプ])で説明した内容と同じなので割愛します。

次は指定時間経過毎にだけ処理をする関数を作成するのですが、
タイマー関連の処理を作成するわけでは無く、約30分毎に処理をしてくれれば良いので、OnTimer()イベント関数を使わずに
上記関数を流用した関数を作成します。


ソースコード:
//+------------------------------------------------------------------+
//| 指定時間足確定時の処理
//+------------------------------------------------------------------+
void TaskSetMinPeriod() {
    static    datetime s_lastset_mintime;               // 最後に記録した時間軸時間
                                                        // staticはこの関数が終了してもデータは保持される

    datetime temptime    = iTime( Symbol(), PERIOD_M30 ,0 );  // 現在の時間軸の時間取得

    if ( temptime == s_lastset_mintime ) {                 // 時間に変化が無い場合
        return;                                         // 処理終了
    }
    s_lastset_mintime = temptime;                          // 最後に記録した時間軸時間を保存

    // ----- 処理はこれ以降に追加 -----------

    printf( "[%d]指定時間足確定%s" , __LINE__ , TimeToStr( Time[0] ) );
}


処理の違いはiTime()関数で30分足を指定して時間を取得している所だけです。

作成した2つの関数をOnTick()関数イベントの処理に追加します。

ソースコード:
//+------------------------------------------------------------------+
//| tick受信イベント
//| EA専用のイベント関数
//+------------------------------------------------------------------+
void OnTick()
{
    TaskPeriod();                   // ローソク足確定時の処理
    TaskSetMinPeriod();             // 指定時間足確定時の処理
}

//+------------------------------------------------------------------+



こうする事で、イベント関数内に長々とソースコードを書く事が無くなります。
ここまで作成したら動作チェックしましょう。
MT4でCtrl+Rを押してストラテジーテスターを開きます。

EA作成1

テスターで上図のように設定して、スタートボタンを押します。
テストが終わったら「操作履歴」でログを確認します。

EA作成1

5分毎と30分毎に関数が呼ばれている事を確認します。
動作チェックが終わったらログ出力部分は削除して大丈夫です。

EAの基礎作成(テスト用オブジェクト描画)

作成のEAをテストする時に役に立つオブジェクト描画をする関数を用意します。
チャートを見ながらテストする時に重宝します。

ソースコード:
//+------------------------------------------------------------------+
//| テスト用オブジェクト描画
//+------------------------------------------------------------------+
void TestDispObject( int    in_index ) {

    // インデックスが範囲外の場合は描画しない
    if ( in_index < 0 ) {
        return;
    }

    if ( in_index >= Bars ) {
        return;
    }

    string obj_name;            // オブジェクト名
    obj_name = StringFormat( "%sEATest%s" , OBJ_HEAD, TimeToStr( Time[in_index] ) );

    if ( ObjectFind( obj_name ) >= 0 ) {  // オブジェクト名重複チェック
        // 重複している場合
        
        ObjectDelete( obj_name );        // 指定したオブジェクトを削除する
    }


    ObjectCreate(                                  // オブジェクト生成
                    obj_name,                        // オブジェクト名
                    OBJ_ARROW_RIGHT_PRICE,        // オブジェクトタイプ
                    0,                               // ウインドウインデックス
                    Time[in_index] ,                // 1番目の時間のアンカーポイント
                    Close[in_index]                // 1番目の価格のアンカーポイント
                    );


    // オブジェクトプロパティ設定
    ObjectSetInteger( 0, obj_name, OBJPROP_COLOR, clrYellow);     // ラインの色設定
    ObjectSetInteger( 0, obj_name, OBJPROP_WIDTH, 1);            // ラインの幅設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_BACK, false);         // オブジェクトの背景表示設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_SELECTABLE, false);   // オブジェクトの選択可否設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_SELECTED, false);     // オブジェクトの選択状態
    ObjectSetInteger( 0 ,obj_name, OBJPROP_HIDDEN, true);        // オブジェクトリスト表示設定
}


define追加と、アンロードイベントでオブジェクト削除する事も忘れずに。

ソースコード:
// マクロ定義
#define    OBJ_HEAD              ( __FILE__ + "_" )  // オブジェクトヘッダ名

//+------------------------------------------------------------------+
//| OnDeinit(アンロード)イベント
//+------------------------------------------------------------------+
void OnDeinit( const int reason ) {

    if ( IsTesting() == false ) {   // バックテスト時以外
        ObjectsDeleteAll(          // 追加したオブジェクトを全削除
                        0,           // チャートID
                        OBJ_HEAD    // オブジェクト名の接頭辞
                       );
    }

}


IsTesting()関数の判定を入れたのは、バックテスト中に描画したオブジェクトが削除されないようにする為です。

EA作成1

必要な時にこんな感じでチャート上にオブジェクト描画します。

エントリー判定処理作成

EAの基礎を作成したら、エントリー判定処理を作成しましょう。
あくまでエントリー判定だけで、実際にエントリー注文は行いません。

懸案 仕様
エントリー基準 ○短期単純移動平均と長期単純移動平均がクロスした時にエントリーする
○逆にクロスしたらクローズする。
○短期SMA期間は5日、長期SMAは25日で固定
トレードスタイル ○順張りのみ
判定タイミング ○エントリー判定はローソク足確定時に行う
○クローズ判定はローソク足確定時に行う

エントリー部分に関する仕様だけ抜き出しました(クローズ判定部分は分離させました)。
まずは上抜けクロス時の判定を行う処理を作りましょう。
EA作成1

前回のea2.EAの仕様検討で、エントリー基準の詳細についての正解を掲載しませんでしたが、
あれは書き忘れたわけではありません。
初心者がほぼ必ずやってしまう失敗例を実演する為に正解を書きませんでした。

とりあえず5SMAと25SMAをiMA()関数で取得しなければならないという事は分かるを思います。

ソースコード:
//+------------------------------------------------------------------+
//| 移動平均線のクロス判定
//+------------------------------------------------------------------+
bool MACrossJudge(){
    
    bool ret = false;
    
    double base_short_ma_rate;  // 確定した短期移動平均
    double base_middle_ma_rate; // 確定した長期移動平均
    
    // 確定した短期SMAを取得
    base_short_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             5,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );

    // 確定した長期SMAを取得
    base_middle_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             25,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );


    // 短期SMAが長期SMAを上抜け
    if ( base_short_ma_rate > base_middle_ma_rate  ) {
        ret = true;
    }
    
    if ( ret == true ) {
        TestDispObject(1); // テスト用オブジェクトを描画
    }
    
    return ret;
}


エントリー判定はローソク足確定時に行うので、この関数をTaskPeriod()で呼び出して下さい。
EA作成1

これでバックテストしてみましょう。
見た目で動作確認をするのでビジュアルモードにチェックを入れて下さい。

EA作成1

見て分かると思いますが、これは狙った動作ではありませんね。
いえ、初心者が必ずやってしまう典型パターンなのである意味狙った動作ですがw

エントリー判定処理の修正

現状動作と作成したプログラムと仕様を見比べて、不具合の原因を調べてどう修正すれば良いか考えます。
というかどう修正すれば良いか考えて下さい。
ここで「何か上手く動作しません、どう修正すればいいですか?」と他人に聞くのはNGです。

という事で前回出したヒントを見てみましょう。
EA作成1

今現状のプログラムで処理をしている部分はどこでしょう?

ソースコード:
    // 短期SMAが長期SMAを上抜け
    if ( base_short_ma_rate > base_middle_ma_rate  ) {
        ret = true;
    }


EA作成1

プログラムで処理されている部分を追記してみました。
流石にここまでヒントを出せば不具合の原因は分かりましたよね?

2つの移動平均線がクロスしたタイミングだけを知りたいので、状況変化を判断する必要があります。
状況変化を判断するには時間要素も考慮しなければなりません。

なので、短期SMAが長期SMAの下で推移している状態から、短期SMAが長期SMAを上抜いた時に移動平均がクロスしたと判断します。
B1がA1より下で、B2がA2より上。もうこれはそのままプログラムに落とし込めるレベルですよね?

さっそくプログラムに追加しましょう。
ソースコード:
//+------------------------------------------------------------------+
//| 移動平均線のクロス判定
//+------------------------------------------------------------------+
bool MACrossJudge(){
    
    bool ret = false;
    
    double base_short_ma_rate;  // 確定した短期移動平均
    double base_middle_ma_rate; // 確定した長期移動平均

    double last_short_ma_rate;  // 前回の短期移動平均
    double last_middle_ma_rate; // 前回の長期移動平均
    
    // 確定した短期SMAを取得
    base_short_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             5,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );

    // 確定した長期SMAを取得
    base_middle_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             25,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );

    // 前回の短期SMAを取得
    last_short_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             5,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             2               // シフト
                        );

    // 前回の長期SMAを取得
    last_middle_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             25,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             2               // シフト
                        );


    // 短期SMAが長期SMAを上抜け
    if (  base_short_ma_rate > base_middle_ma_rate  
       && last_short_ma_rate < last_middle_ma_rate
    ) {
        ret = true;
    }
    
    if ( ret == true ) {
        TestDispObject(1); // テスト用オブジェクトを描画
    }
    
    return ret;
}



EA作成1

動作確認すると、上抜けたタイミングでのみオブジェクト描画されているのが確認出来ました。

EA作成1

図を見ても理解できると思いますが、何かの変化を判断するには「時間」の考慮が必要です。
変化したか否かは、それ以前の状況と比較する必要があります。当然変化後だけの状況を見ても、比較対象が存在しないのでそれが変化後なのかは分かりません。

「そんなの当たり前じゃねーか!」と言う人がいるかもしれませんが、
そういう人はその当たり前の事を論理的に説明できず後出しジャンケンでまるで最初から知っていたかのように振る舞う文句だけは一人前の会社の無能上司と同じです。 最初から知っていたのなら他の人間が答えを言う前に答えを言えばいいのにw
EA作成1

これはプログラムに落とし込めるか以前の問題で、論理的に物事を考えられるかが問われます。
まずは論理的に物事を考えて、それを言葉で表現する、言葉で表現した内容をプログラムに落とし込む。
そもそも言葉で表現出来ない人はプログラムに落とし込む事が出来ません、何故なら何をして良いのかが未だ分かっていないのですから。
言葉で上手く表現出来ない人はとにかく絵や図を描いて、自分のやりたい事をなんとか言葉で表現するようによく考える必要があります。 プログラミング未経験者で言葉で表現する事が苦手な人程この作業をしっかり行って下さい、苦手でも経験を蓄積させる事で出来るようになります。
EA設計

ここで考える事を放棄して他人に助けを求める人は思考停止状態に陥ります。
脳は考える事を放棄する事によってドーパミンが分泌されて快感を得てしまい、それが癖になってしまうので要注意。
考える事を放棄する事が癖になっている人は会社にいませんか?会社が大きければ大きいほどそういう社員が多い筈です。 それがまかり通るのは時間拘束を対価に給与が貰えるのと、仕事をしない正社員をクビにする事が出来ない過保護な法律に守られている事と、 上司のイエスマンにさえ徹していれば現場での居場所が無くならない馴れ合い社会が確立しているからです。 だから日本の会社は考えることを放棄する社員で溢れます。

下抜けエントリー判定を追加

上抜けエントリー判定の処理が出来上がってから、下抜けエントリー判定の処理を追加します。
慣れてきたら同時に作成しても良いのですが、初心者の時は不具合を見つけ易くなるように、
このように一つ一つ確実に作成します。

最初から取引関数でエントリー発注させないもの、取引関数の使い方に不具合があるのか?エントリー判定に不具合があるのか?
を明確に出来るからです。
今は未だ取引関数を使っていないので、問題があれば確実にエントリー判定による不具合である事は確実です。

それでは下抜けエントリー判定を追加しましょう。
ソースコード:
    // 短期SMAが長期SMAを上抜け
    if (  base_short_ma_rate > base_middle_ma_rate  
       && last_short_ma_rate < last_middle_ma_rate
    ) {
        ret = true;
    }
    else if ( base_short_ma_rate < base_middle_ma_rate  
            && last_short_ma_rate > last_middle_ma_rate
    ) {
        // 短期SMAが長期SMAを下抜け
        ret = true;
    }


EA作成1

エントリー判定結果にenum列挙を使う

SMAの上抜けと下抜けの判定処理は出来ましたが、結果での判断が出来ないのでenum列挙を追加します。

ソースコード:
// enum列挙型宣言
enum ENUM_MA_CROSS {                            // 移動平均クロス列挙
    MAC_NO = 0,                                 // 無し
    MAC_UP_CHANGE,                              // MA上抜け
    MAC_DOWN_CHANGE                             // MA下抜け
};


enum列挙を追加したら戻り値の型をboolからENUM_MA_CROSSに変更します。

ソースコード:
//+------------------------------------------------------------------+
//| 移動平均線のクロス判定
//+------------------------------------------------------------------+
ENUM_MA_CROSS MACrossJudge(){
    
    ENUM_MA_CROSS ret = MAC_NO;
    


    //~中略~



    // 短期SMAが長期SMAを上抜け
    if (  base_short_ma_rate > base_middle_ma_rate  
       && last_short_ma_rate < last_middle_ma_rate
    ) {
        ret = MAC_UP_CHANGE;
    }
    else if ( base_short_ma_rate < base_middle_ma_rate  
            && last_short_ma_rate > last_middle_ma_rate
    ) {
        // 短期SMAが長期SMAを下抜け
        ret = MAC_DOWN_CHANGE;
    }

    if ( ret == MAC_UP_CHANGE || ret == MAC_DOWN_CHANGE ) {
        TestDispObject(1); // テスト用オブジェクトを描画
    }

    return ret;
}


動作上は変化がありませんが、これは後で取引関数を実装する時に必要になります。
動作確認したらテスト用オブジェクト描画の呼び出しは不要なのでコメントアウトしておきます。

あと地味な事なのですが、条件判定文が複数ある場合は、判定する変数や不等号の位置を揃える事で、
ソースコードが見易くなりますので、こういう地味な工夫をする事でデバッグ等の時間短縮になります。
EA作成1
EA作成1

あくまで本人が見易くなる為の工夫なので、どんな感じに揃えるかは人それぞれになります。
これも新卒社員や外注SESに何度も何度も言っているのですが、日本語が通じないのか列を揃えてくれません。
結局上手く動作せずにヘルプを出されて、グチャグチャのソースコードを整列させてみると、if分判定の不等号の間違いが直ぐに見つかります。
そしてこの失敗を何度も繰り返します。デジャブどころか新しくやって来た社員の鉄板の行動パターンです。


不具合修正

ご指摘があって検証した結果、不具合がある事が確認出来ました。
短期SMAと長期SMAの値が一致するパターンがあった場合、正しく条件判定が行われなくなります。
EA作成1

異なる期間の平均値の浮動小数点数なので完全一致する確率は非常に低いのですが、理屈上は不具合になるパターンが存在しているので修正する必要があります。

ちなみに実際の平均値は以下の通りです。
1万件程テストしましたが、完全一致したパターンは検出されませんでした。

ログ:
2020.11.05 00:23, 104.5040000000008, 104.50356
2020.11.05 00:22, 104.5038000000008, 104.50348
2020.11.05 00:21, 104.5032000000008, 104.50316
2020.11.05 00:20, 104.5028000000008, 104.5026
2020.11.05 00:19, 104.5036000000008, 104.50244
2020.11.05 00:18, 104.5042000000008, 104.5022399999999
2020.11.05 00:17, 104.5046000000008, 104.5020799999999
2020.11.05 00:16, 104.5054000000008, 104.5017999999999
2020.11.05 00:15, 104.5054000000008, 104.5015999999999
2020.11.05 00:14, 104.5046000000008, 104.5010399999999
2020.11.05 00:13, 104.5042000000008, 104.5004799999999
2020.11.05 00:12, 104.5054000000008, 104.4997599999999
2020.11.05 00:11, 104.5100000000008, 104.4991599999999
2020.11.05 00:10, 104.5106000000008, 104.4987999999999
2020.11.05 00:08, 104.5116000000008, 104.4986799999999

不等号部分を以下の通りに修正します。
EA作成1

ソースコード:
//+------------------------------------------------------------------+
//| 移動平均線のクロス判定
//+------------------------------------------------------------------+
ENUM_MA_CROSS MACrossJudge(){
    
    ENUM_MA_CROSS ret = MAC_NO;
    


    //~中略~



    // 短期SMAが長期SMAを上抜け
    if (  base_short_ma_rate > base_middle_ma_rate  
       && last_short_ma_rate <= last_middle_ma_rate
    ) {
        ret = MAC_UP_CHANGE;
    }
    else if ( base_short_ma_rate < base_middle_ma_rate  
            && last_short_ma_rate >= last_middle_ma_rate
    ) {
        // 短期SMAが長期SMAを下抜け
        ret = MAC_DOWN_CHANGE;
    }

    if ( ret == MAC_UP_CHANGE || ret == MAC_DOWN_CHANGE ) {
        TestDispObject(1); // テスト用オブジェクトを描画
    }

    return ret;
}


もしかしたら他にも不具合があるかもしれませんが、不具合を完全に取り除く事は不可能です。
異なる期間の平均値の浮動小数点数なので完全一致する確率は非常に低く、
またEA作成の基本を習得する事が目的なので、多少妥協しても問題は無いと考えます。

もしどうしても気になるパターンがあって検証したい人は
EA作成1

エクセル(数式が使える表計算ソフトなら何でも良いです)の数式を使って、テストパターンを検証してみて下さい。
もし何か不具合が発生するパターンを発見したら、条件を追加してエクセルで検証して自力で修正してみて下さい。



進捗状況確認

懸案 仕様
エントリー基準 ◎短期単純移動平均と長期単純移動平均がクロスした時にエントリーする
○逆にクロスしたらクローズする。
●短期SMA期間は5日、長期SMAは25日で固定
トレードスタイル ○順張りのみ
リミット・ストップ ○リミットは20%に設定
○ストップは10%に設定
○エントリー直後に入れる必要は無い
○トレーリングストップはしない
判定タイミング ◎エントリー判定はローソク足確定時に行う
○クローズ判定はローソク足確定時に行う
○リミット・ストップは指定時間経過毎に行う(30分毎)
建玉と増玉 ○増玉はしない
○ロットは最小ロット固定

仕様変更した内容を適用しました。
部分実装した箇所は◎にし、実装済み箇所は●に変更しました。
こんな感じで進捗状況を確認したり、変更した仕様変更内容を確認しながらEA作成を進めましょう。

ここまでの説明で分からない所があるという人は・・・読み飛ばしてここのページだけを見ていませんか?
既に知っていて分かっているから読み飛ばしたんですよね?


それからテスト用に描画していたオブジェクト表示はもう不要なので、コメントアウトします。
また想定していない動作をしたりデバッグする時に使用するかもしれないので削除では無く、コメントアウトにしておいていつでも表示出来るようにします。

ソースコード:
    // if ( ret == MAC_UP_CHANGE || ret == MAC_DOWN_CHANGE ) {
    //      TestDispObject(1); // テスト用オブジェクトを描画
    // }


完成したサンプルソースコード


ソースコード:
//+------------------------------------------------------------------+
//|                                                  TestMACross.mq4 |
//|                                                             yuki |
//|                                      https://yukifx.web.fc2.com/ |
//+------------------------------------------------------------------+
#property copyright "yuki"
#property link      "https://yukifx.web.fc2.com/"
#property version   "1.00"
#property strict // strictは絶対に削除しない事

// マクロ定義
#define    OBJ_HEAD              ( __FILE__ + "_" )  // オブジェクトヘッダ名

// enum列挙型宣言
enum ENUM_MA_CROSS {                            // 移動平均クロス列挙
    MAC_NO = 0,                                 // 無し
    MAC_UP_CHANGE,                              // MA上抜け
    MAC_DOWN_CHANGE                             // MA下抜け
};


//+------------------------------------------------------------------+
//| OnInit(初期化)イベント
//+------------------------------------------------------------------+
int OnInit()
{
    if ( IsDemo() == false ) {            // デモ口座以外の場合
        Print("デモ口座でのみ動作します");
        return INIT_FAILED;                            // 処理終了
    }

    return( INIT_SUCCEEDED );      // 戻り値:初期化成功
}

//+------------------------------------------------------------------+
//| OnDeinit(アンロード)イベント
//+------------------------------------------------------------------+
void OnDeinit( const int reason ) {

    if ( IsTesting() == false ) {   // バックテスト時以外
        ObjectsDeleteAll(          // 追加したオブジェクトを全削除
                        0,           // チャートID
                        OBJ_HEAD    // オブジェクト名の接頭辞
                       );
    }

}

//+------------------------------------------------------------------+
//| tick受信イベント
//| EA専用のイベント関数
//+------------------------------------------------------------------+
void OnTick()
{

    TaskPeriod();                   // ローソク足確定時の処理
    TaskSetMinPeriod();             // 指定時間足確定時の処理

}

//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| ローソク足確定時の処理
//+------------------------------------------------------------------+
void TaskPeriod() {
    static    datetime s_lasttime;                      // 最後に記録した時間軸時間
                                                        // staticはこの関数が終了してもデータは保持される

    datetime temptime    = iTime( Symbol(), Period() ,0 );  // 現在の時間軸の時間取得

    if ( temptime == s_lasttime ) {                     // 時間に変化が無い場合
        return;                                         // 処理終了
    }
    s_lasttime = temptime;                              // 最後に記録した時間軸時間を保存

    // ----- 処理はこれ以降に追加 -----------
    MACrossJudge();                                   // 移動平均線のクロス判定

    // printf( "[%d]ローソク足確定%s" , __LINE__ , TimeToStr( Time[0] ) );
}

//+------------------------------------------------------------------+
//| 指定時間足確定時の処理
//+------------------------------------------------------------------+
void TaskSetMinPeriod() {
    static    datetime s_lastset_mintime;               // 最後に記録した時間軸時間
                                                        // staticはこの関数が終了してもデータは保持される

    datetime temptime    = iTime( Symbol(), PERIOD_M30 ,0 );  // 現在の時間軸の時間取得

    if ( temptime == s_lastset_mintime ) {                 // 時間に変化が無い場合
        return;                                         // 処理終了
    }
    s_lastset_mintime = temptime;                          // 最後に記録した時間軸時間を保存

    // ----- 処理はこれ以降に追加 -----------

    // printf( "[%d]指定時間足確定%s" , __LINE__ , TimeToStr( Time[0] ) );

}

//+------------------------------------------------------------------+
//| テスト用オブジェクト描画
//+------------------------------------------------------------------+
void TestDispObject( int    in_index ) {

    // インデックスが範囲外の場合は描画しない
    if ( in_index < 0 ) {
        return;
    }

    if ( in_index >= Bars ) {
        return;
    }

    string obj_name;            // オブジェクト名
    obj_name = StringFormat( "%sEATest%s" , OBJ_HEAD, TimeToStr( Time[in_index] ) );

    if ( ObjectFind( obj_name ) >= 0 ) {  // オブジェクト名重複チェック
        // 重複している場合
        
        ObjectDelete( obj_name );        // 指定したオブジェクトを削除する
    }


    ObjectCreate(                                  // オブジェクト生成
                    obj_name,                        // オブジェクト名
                    OBJ_ARROW_RIGHT_PRICE,        // オブジェクトタイプ
                    0,                               // ウインドウインデックス
                    Time[in_index] ,                // 1番目の時間のアンカーポイント
                    Close[in_index]                // 1番目の価格のアンカーポイント
                    );


    // オブジェクトプロパティ設定
    ObjectSetInteger( 0, obj_name, OBJPROP_COLOR, clrYellow);     // ラインの色設定
    ObjectSetInteger( 0, obj_name, OBJPROP_WIDTH, 1);            // ラインの幅設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_BACK, false);         // オブジェクトの背景表示設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_SELECTABLE, false);   // オブジェクトの選択可否設定
    ObjectSetInteger( 0 ,obj_name, OBJPROP_SELECTED, false);     // オブジェクトの選択状態
    ObjectSetInteger( 0 ,obj_name, OBJPROP_HIDDEN, true);        // オブジェクトリスト表示設定
}

//+------------------------------------------------------------------+
//| 移動平均線のクロス判定
//+------------------------------------------------------------------+
ENUM_MA_CROSS MACrossJudge(){
    
    ENUM_MA_CROSS ret = MAC_NO;

    double base_short_ma_rate;  // 確定した短期移動平均
    double base_middle_ma_rate; // 確定した長期移動平均

    double last_short_ma_rate;  // 前回の短期移動平均
    double last_middle_ma_rate; // 前回の長期移動平均
    
    // 確定した短期SMAを取得
    base_short_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             5,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );

    // 確定した長期SMAを取得
    base_middle_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             25,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             1               // シフト
                        );

    // 前回の短期SMAを取得
    last_short_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             5,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             2               // シフト
                        );

    // 前回の長期SMAを取得
    last_middle_ma_rate = iMA (               // 移動平均算出
                             Symbol(),      // 通貨ペア
                             Period(),      // 時間軸
                             25,             // MAの平均期間
                             0,              // MAシフト
                             MODE_SMA,     // MAの平均化メソッド
                             PRICE_CLOSE,  // 適用価格
                             2               // シフト
                        );


    // 短期SMAが長期SMAを上抜け
    if (  base_short_ma_rate > base_middle_ma_rate  
       && last_short_ma_rate <= last_middle_ma_rate
    ) {
        ret = MAC_UP_CHANGE;
    }
    else if ( base_short_ma_rate < base_middle_ma_rate  
            && last_short_ma_rate >= last_middle_ma_rate
    ) {
        // 短期SMAが長期SMAを下抜け
        ret = MAC_DOWN_CHANGE;
    }

    // if ( ret == MAC_UP_CHANGE || ret == MAC_DOWN_CHANGE ) {
    //      TestDispObject(1); // テスト用オブジェクトを描画
    // }

    return ret;
}



スポンサーリンク


Copyright ©2015 MT4でEA自作しちゃお~ All Rights Reserved.


Top

inserted by FC2 system