億トレを達成したMTFダブルブレイクアウト手法を検証してみた
ダブルブレイクアウト時エントリーする手法をEA化しました。
ちょっと難しく、間違ってたらごめんなさい。
ダブルブレイクアウト手法のEA化によるトレード戦略の検証
はじめに
この記事では、トレード手法の開発とその自動化に焦点を当て、特にダブルブレイクアウト手法について詳しく説明します。この手法は相場の方向性を判断し、エントリーポイントを特定するために様々な要素を組み合わせたものです。手法の詳細やトレンドの判定方法、利確損切り戦略について詳しく解説します。
手法の詳細
1. トレンドの判定
まず、トレンドの方向性を判断するために、4時間足の25期間移動平均線(25MA)を使用します。これにより、現在の市場の傾向を把握します。
2. ボックス相場の特定
次に、15分足のチャートを使用してボックス相場を特定します。ボックス相場は移動平均線とのクロスの回数を基準に判断します。ボックス相場は相場が一定の価格範囲内で動いている状況を指します。
3. ブレイクアウトの検出
15分足のボックス相場が特定されたら、そのボックスの範囲をブレイクアウトするポイントを探します。ブレイクアウトが発生したら、次に注目するのは次の15分足のローソク足です。
4. 反発の確認
ブレイクアウト後、次の15分足のローソク足がボックスの範囲に戻り、反発していることを確認します。この反発は新しいトレンドの始まりを示す可能性が高いです。
5. エントリーポイントの確定
最後に、5分足のチャートを使用してブレイクアウトの反発を確認し、順張りエントリーポイントを確定します。
利確損切り戦略
利確損切りポイントについては、80PIPSを基本的なポイントとして設定しています。ただし、ポイントの詳細な理由については言及されていません。
状態の変化
このトレード手法は、以下のように状態が変化します。
準備1
A下降トレンドを判定
Bボックス相場を判定
Cボックスブレイクアウトを判定
ABCの条件を満たす場合、準備1の状態となります。
準備1の状態
D戻りを判定
Dの条件を満たす場合、準備2の状態に進みます。
準備2
Eブレイクを判定
Eの条件を満たす場合、エントリーのタイミングとなります。ただし、A否定やB否定の条件があればエントリーは見送ります。
バックテスト
ソースコード
//+------------------------------------------------------------------+
//| ProjectName |
//| Copyright 2018, CompanyName |
//| http://www.companyname.net |
//+------------------------------------------------------------------+
#property strict
int MagicNumber = 789;
// ブレイクアウト後の戻りを判定する関数
bool is_breakout_retreat(int side)
{
int bars = 1; // 直近の1本のローソク足をチェック
double current_open = iOpen(NULL, PERIOD_M15, bars); // 直近のローソク足のopen
double current_close = iClose(NULL, PERIOD_M15, bars); // 直近のローソク足のclose
if (side == 1 && current_close > current_open) {
return true; // 上昇判定
} else if (side == 0 && current_close < current_open) {
return true; // 下降判定
}
return false; // 戻りがない場合または判定条件に合わない場合、falseを返す
}
double get_high_or_low_price(string side, int bars)
{
ENUM_TIMEFRAMES timeframe;
// barsの値に応じて時間枠を選択
if (bars == 15) {
timeframe = PERIOD_M15;
} else if (bars == 5) {
timeframe = PERIOD_M5;
} else {
// サポートされていないバー数が指定された場合、エラー値を返す
return -1.0;
}
double price;
if (side == "high") {
int index = iHighest(NULL,timeframe,MODE_HIGH, range, 1);
price = iHigh(NULL, timeframe, index);
} else if (side == "low") {
int index = iLowest(NULL, timeframe, MODE_LOW, range, 1);
price = iLow(NULL, timeframe, index);
} else {
// サポートされていないsideが指定された場合、エラー値を返す
return -1.0;
}
return price;
}
bool is_box_Break(int side,int bars)
{
double current_price;
double reference_price;
if (side == 0) {
// 高値をチェック
current_price = iHigh(NULL, bars, 0); // 現在の高値を取得
reference_price = get_high_or_low_price("high",bars); // 過去30本の最高値を取得
} else if (side == 1) {
// 安値をチェック
current_price = iLow(NULL, bars, 0); // 現在の安値を取得
reference_price = get_high_or_low_price("low",bars); // 過去30本の最安値を取得
} else {
return false; // 不正なサイドが指定された場合、falseを返す
}
if (current_price > reference_price) {
return true; // ブレイクした場合、trueを返す
}
return false; // ブレイクしていない場合、falseを返す
}
input int range = 25;
// ボックスかどうかを判断する関数
bool is_BOX()
{
int count=0;
for(int i = 1; i <= range; i++)
{
//移動平均線 <= 終値
bool up = iMA(NULL,0,20,0,0,0,i+1) <= iClose(NULL,0,i+1);
//移動平均線 >= 終値
bool down = iMA(NULL,0,20,0,0,0,i+1) >= iClose(NULL,0,i+1);
//現在足 移動平均線 <= 終値
bool current_up = iMA(NULL,0,20,0,0,0,i) <= iClose(NULL,0,i);
//現在足 移動平均線 >= 終値
bool current_down = iMA(NULL,0,20,0,0,0,i) >= iClose(NULL,0,i);
//もしもup状態でcurrent_downならクロス
if(up && current_down)
{
count++;
}
//もしもdown状態でcurrent_upならクロス
if(down && current_up)
{
count++;
}
}
if(4 <= count)
{
return true;
}
return false;
}
// 4時間足SMA25が上昇または下降しているかどうかを判定する関数
bool IsFourHourSMA25Trend(int side)
{
double sma25_current, sma25_previous;
// 4時間足(240分足)のSMA25を計算
sma25_current = iMA(Symbol(), PERIOD_H4, 25, 0, MODE_SMA, PRICE_CLOSE, 0);
sma25_previous = iMA(Symbol(), PERIOD_H4, 25, 0, MODE_SMA, PRICE_CLOSE, 1);
if (side == 0) {
// 上昇しているかどうかを判定
if (sma25_current > sma25_previous) {
return true; // 上昇している場合、trueを返す
}
} else if (side == 1) {
// 下降しているかどうかを判定
if (sma25_current < sma25_previous) {
return true; // 下降している場合、trueを返す
}
}
return false; // 上昇または下降していない場合、falseを返す
}
bool is_buy(){
static datetime prev_time = iTime(NULL,15,0);
static bool junbi1 = false;
static bool junbi2 = false;
bool A,B,C,D,E;
A = IsFourHourSMA25Trend(0);
B = is_BOX();
C = is_box_Break(0,15);
D = is_breakout_retreat(0);
E = is_box_Break(0,5);
if(A&&B&&C){junbi1 = true;prev_time = iTime(NULL,15,0);}
if(junbi1){
if(prev_time==iTime(NULL,15,2)){
if(D){junbi1 = false;junbi2=true;}else{junbi1 = false;}}
}
if(junbi2){if(E){junbi2=false;return true;}
if(!A || !B){junbi2=false;}
}
return false;}
bool is_sell()
{
static datetime prev_time = iTime(NULL,15,0);
static bool junbi1 = false;
static bool junbi2 = false;
bool A, B, C, D, E;
A = IsFourHourSMA25Trend(1); // 1を指定して下降トレンドを判定
B = is_BOX(); // 1を指定して下降ボックスを判定
C = is_box_Break(1, 15); // 1を指定して15バーの下降ボックスブレイクを判定
D = is_breakout_retreat(1); // 1を指定して下降戻りを判定
E = is_box_Break(1, 5); // 1を指定して5バーの下降ボックスブレイクを判定
if(A&&B&&C){junbi1 = true;prev_time = iTime(NULL,15,0);}
if(junbi1){
if(prev_time==iTime(NULL,15,2)){
if(D){junbi1 = false;junbi2=true;}else{junbi1 = false;}}
}
if(junbi2){if(E){junbi2=false;return true;}
if(!A || !B){junbi2=false;}
}
return false;
}
void OnTick()
{
//エントリー
if(position_count(OP_BUY)==0 && position_count(OP_SELL)==0 && is_buy())
{
position_entry(OP_BUY);
}
if(position_count(OP_BUY)==0 && position_count(OP_SELL)==0 && is_sell())
{
position_entry(OP_SELL);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int position_count(int side)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
count++;
}
}
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
input int SL = 800;
input int TP = 800;
void position_entry(int side)
{
double qty = 0.1;
double entryPrice = 0.0;
double slPrice = 0.0;
double tpPrice = 0.0;
if (side == 0)
{
entryPrice = Ask;
slPrice = entryPrice - SL * Point; // SLはエントリー価格から200 * Point下に設定
tpPrice = entryPrice + TP * Point; // TPはエントリー価格から200 * Point上に設定
int ticket = OrderSend(NULL, side, qty, entryPrice, 0, slPrice, tpPrice, NULL, MagicNumber, 0, clrGreen);
if (ticket > 0)
{
Print("Long Order Placed. Ticket: ", ticket);
}
else
{
Print("Error placing Long Order. Error code: ", GetLastError());
}
}
else if (side == 1)
{
entryPrice = Bid;
slPrice = entryPrice + SL * Point; // SLはエントリー価格から200 * Point上に設定
tpPrice = entryPrice - TP * Point; // TPはエントリー価格から200 * Point下に設定
int ticket = OrderSend(NULL, side, qty, entryPrice, 0, slPrice, tpPrice, NULL, MagicNumber, 0, clrRed);
if (ticket > 0)
{
Print("Short Order Placed. Ticket: ", ticket);
}
else
{
Print("Error placing Short Order. Error code: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void position_close(int side)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == side)
{
if(OrderSymbol()==Symbol())
{
if(OrderMagicNumber()==MagicNumber)
{
bool res= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0, clrBlue);
}
}
}
}
}
}