【FX検証】前日の高値・安値ブレイク手法の検証~戦略のコード化~

FX

前回までには戦略を明文化することろまで行きました。

今回は、この戦略を実際にコード化するところまでを公開していきいます。

戦略の概要をおさらい

今回作成するトレード戦略の概要をもう一度おさらいしておきます。


【仕掛けルール】

X日間の高値の最大値をY時間足の実体で更新したらロング
X日間の安値の最小値をY時間足の実体で更新したらショート

最適化対象パラメータ:X、Y

ただし、パラメータYは多期間多市場テストの一環で堅牢性を確かめるとともに、最適化するものとする。

【手仕舞いルール】

ドテン戦略

戦略のコード化 ver1

#property strict
//--- input parameters
input int      slippage=10;
input int      day_count=3;//X日間の最高値/最安値
extern int     magicnumber=123;
//input int      time_frame;//Y時間足 多市場多期間テストで最適化→手動で調整
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
/*-----------------------------------------------------------------------------------

【仕掛けルール】

X日間の高値の最大値をY時間足の実体で更新したらロング
X日間の安値の最小値をY時間足の実体で更新したらショート

最適化対象パラメータ:
X→day_count

ただし、パラメータYは多期間多市場テストの一環で堅牢性を確かめるとともに、最適化するものとする。


【手仕舞いルール】
ドテン
ただしデイトレード戦略を保ちたいので、ロンドン時間の引けと同時に手仕舞い←これは後回し

-------------------------------------------------------------------------------------*/
void OnTick()
  {
  int Index_high=iHighest(NULL,0,MODE_HIGH,day_count,1);//ひとつ前の足から、day_count本前までの中での高値を抽出
  int Index_low=iLowest(NULL,0,MODE_LOW,day_count,1);//ひとつ前の足から、day_count本前までの中での最安を抽出
  double close=iClose(NULL,0,0);//最新の終値を参照
  
  double highest=High[Index_high];//抽出した高値の中から、最高値を選ぶ
  double lowest=Low[Index_low];//抽出した安値の中から、最安値を選ぶ
  
  
  if((close < lowest) && OrdersTotal()==1)close_sell();//ショート手仕舞いの条件 ドテン
  if((close > highest)&& OrdersTotal()==1)close_buy();//ロング手仕舞いの条件 ドテン
  
  
  if((close > highest) && OrdersTotal()==0)//ロングの条件
  {
   printf("ロング");      
   OrderSend(Symbol(),OP_BUY,1,Ask,slippage,0,0,NULL,magicnumber,0,clrRed);//損切り、利確:指定なし,lot:1   
  }
  
  if((close < lowest) && OrdersTotal()==0)//ショートの条件
  {
   printf("ショート");      
   OrderSend(Symbol(),OP_SELL,1,Bid,slippage,0,0,NULL,magicnumber,0,clrBlue);//損切り、利確:指定なし,lot:1   
  }
  
  Comment(day_count+1,"期間の最高値は",highest,"|",
          day_count+1,"期間の最安値は",lowest);
  
//---
   
  }
  
void close_buy()
  {
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)break;
      if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magicnumber)continue;
      if(OrderType()==OP_BUY)OrderClose(i,OrderLots(),Bid,slippage,clrRed);
   }
  }

void close_sell()
  {
   for(int i=0;i<OrdersTotal();i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)break;
      if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magicnumber)continue;
      if(OrderType()==OP_SELL)OrderClose(i,OrderLots(),Ask,slippage,clrBlue);
   }
  }

最初にこのようにコードを組み、無事コンパイルできたのですが、注文が一つしか実行されないという問題が発生しました。

原因がよくわからなかったので、今流行りのChatgptに訂正してもらいました。まじで便利な時代になりましたね。

コードの最終版

input int slippage = 10;
input int day_count = 3;
extern int magicnumber = 123;

int currentTradeType = -1; // -1: 保有ポジションなし, 0: ロングポジション, 1: ショートポジション

void OnTick()
{
    double highest = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, day_count, 1));
    double lowest = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, day_count, 1));
    double close = iClose(NULL, 0, 0);

    if (currentTradeType == 0 && close < lowest)
        close_long(); // ロング手仕舞いの条件 ドテン
    else if (currentTradeType == 1 && close > highest)
        close_short(); // ショート手仕舞いの条件 ドテン
    else if (currentTradeType == -1 && close > highest) // ロングの条件
    {
        printf("ロング");
        OrderSend(Symbol(), OP_BUY, 1, Ask, slippage, 0, 0, NULL, magicnumber, 0, clrRed);
        currentTradeType = 0; // ロングポジションをトラッキング
    }
    else if (currentTradeType == -1 && close < lowest) // ショートの条件
    {
        printf("ショート");
        OrderSend(Symbol(), OP_SELL, 1, Bid, slippage, 0, 0, NULL, magicnumber, 0, clrBlue);
        currentTradeType = 1; // ショートポジションをトラッキング
    }

    Comment(day_count + 1, "期間の最高値は", highest, "|",
            day_count + 1, "期間の最安値は", lowest);
}

void close_long()
{
    for (int i = 0; i < OrdersTotal(); i++)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
            break;
        if (OrderSymbol() != Symbol() || OrderMagicNumber() != magicnumber)
            continue;
        if (OrderType() == OP_BUY)
        {
            double lots = OrderLots();
            OrderClose(OrderTicket(), lots, Bid, slippage, clrRed);
            currentTradeType = -1; // 保有ポジションなしにリセット
        }
    }
}

void close_short()
{
    for (int i = 0; i < OrdersTotal(); i++)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
            break;
        if (OrderSymbol() != Symbol() || OrderMagicNumber() != magicnumber)
            continue;
        if (OrderType() == OP_SELL)
        {
            double lots = OrderLots();
            OrderClose(OrderTicket(), lots, Ask, slippage, clrBlue);
            currentTradeType = -1; // 保有ポジションなしにリセット
        }
    }
}

実際に、MT4でバックテストしてみると、以上のようにしっかり機能していることが分かります。

次回は最適化の作業を行っていきたいとおもいます。