「コナーズの短期売買実践」のトレード戦略のEA化【第2弾】
前回の記事で書いた仕掛け条件だと、最高値/最安値更新中に次のローソク足が生成された時、意図したギャップにならないことがバックテストして気づいたので、条件を1箇所変更しました。
仕掛け条件(買いの場合)
- 1本前の足を基準に、14本ADX>25でかつ14本+DI>14本分の-DI
- 1本前の足の始値が2本前の高値よりADX_DifPipsを超えて上に位置(ギャップを空けて上昇を表現)
- 現在足の始値で買い(仕掛けの判断は新しい足が生成された時だけ)
では、早速動かしてみましょう。バックテストは以下の条件で実施しました。
- 対象EA:MomentumGap
- 通貨ペア:EURUSD
- ローソク足の種類:日足
- モデル:全ティック
- スプレッド:3pips固定
- バックテスト期間:2008/1/1~2016/7/5
- ヒストリカルデータ:Dukascopy社のJForexからダウンロードした1分足
- 初期口座残高:10,000ドル
- ロット数:0.01固定
結果はこちらです。
よくよく考えると、為替相場は株式相場と違って24h開いているので、ギャップは休場明けの月曜の最初等でしか発生しないんですよね…。完璧に失念していました。
EAのパラメータは適当です。不整合チャートも発生していましたが、気にしないでおきます。
モメンタムギャップ戦略はランナウェイギャップを狙ったものでしたが、為替相場においては、平均値に戻ろうとする力の方が大きいような気がします(トレード回数が少なすぎてボツにしたので、ちゃんと調べていませんが)。
このトレード戦略もダブルボリューム・マーケットトップ戦略と同じで大量の通貨ペアを同時にウォッチして、条件成立の確率を上げないと使えなそうです。次はもっと日中足でも使える戦略を探さないといけませんね!
MomentumGap.mq4のコードを公開しますので、良かったら参考になさってください。
//+------------------------------------------------------------------+ //| MomentumGap.mq4 | //| Copyright (c) 2016, りゅーき | //| https://autofx100.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright (c) 2016, りゅーき" #property link "https://autofx100.com/" #property version "1.00" //+------------------------------------------------------------------+ //| ライブラリ | //+------------------------------------------------------------------+ #include <stderror.mqh> #include <stdlib.mqh> #include <WinUser32.mqh> #include <Original/Application.mqh> #include <Original/Basic.mqh> #include <Original/DateAndTime.mqh> #include <Original/LotSizing.mqh> #include <Original/OrderHandle.mqh> #include <Original/OrderReliable.mqh> //+------------------------------------------------------------------+ //| 定数 | //+------------------------------------------------------------------+ // #define //+------------------------------------------------------------------+ //| EAパラメータ設定情報 | //+------------------------------------------------------------------+ extern string Note01 = "=== General =================================================="; extern int MagicNumber = 7777777; extern int SlippagePips = 5; extern string Comments = ""; extern double FixLotSize = 0.01; extern string Note02 = "=== Entry ===================================================="; extern int ADX_Period = 14; extern double ADX_Value = 25.0; extern double ADX_DifPips = 10.0; extern string Note03 = "=== Exit ====================================================="; extern double SL_Pips = 10.0; extern double TP_Pips = 15.0; extern string Note03_1 = "--- Trailing Stop --------------------------------------------"; extern bool UseTS = false; extern double TS_StartPips = 15.0; extern double TS_StopPips = 10.0; //+------------------------------------------------------------------+ //| グローバル変数 | //+------------------------------------------------------------------+ // 共通 double gPipsPoint = 0.0; int gSlippage = 0; color gArrowColor[6] = {Blue, Red, Blue, Red, Blue, Red}; //BUY: Blue, SELL: Red int gPrvBars = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { gPipsPoint = currencyUnitPerPips(Symbol()); gSlippage = getSlippage(Symbol(), SlippagePips); gPrvBars = Bars; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int currentBars = Bars; // ----------------------------------------------------------------- // 手仕舞い // ----------------------------------------------------------------- if(UseTS){ trailingStopGeneral(MagicNumber, TS_StartPips, TS_StopPips); } // ----------------------------------------------------------------- // 仕掛けフィルター // ----------------------------------------------------------------- // 新しい足を生成した時ではない場合は、仕掛けない if(currentBars == gPrvBars){ gPrvBars = currentBars; return; } // ----------------------------------------------------------------- // 仕掛け // ----------------------------------------------------------------- double ADX = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1); double P_DI = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 1); double M_DI = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 1); double open1 = NormalizeDouble(Open[1], Digits); double high2 = NormalizeDouble(High[2], Digits); double low2 = NormalizeDouble(Low[2], Digits); if(ADX > ADX_Value){ if(P_DI > M_DI){ if(open1 - high2 > ADX_DifPips * gPipsPoint){ int ticket = orderSendReliableRange(Symbol(), OP_BUY, FixLotSize, Ask, gSlippage, SL_Pips, TP_Pips, Comments, MagicNumber, 0, gArrowColor[OP_BUY]); } }else if(M_DI > P_DI){ if(low2 - open1 > ADX_DifPips * gPipsPoint){ ticket = orderSendReliableRange(Symbol(), OP_SELL, FixLotSize, Bid, gSlippage, SL_Pips, TP_Pips, Comments, MagicNumber, 0, gArrowColor[OP_SELL]); } } } // 本来はticketの値によって後続の処理を制御する必要があるが、簡単のため、ここでは無視 gPrvBars = currentBars; }