ブログタイトルを「FX自動売買システム開発部」から「autoFX」に変更しました!

1本の足で1回だけ仕掛ける機能

足(バー)作成直後のみ仕掛ける方法

確定した足をエントリーの条件にしているEA等では、1本の足(バー)で1回しか仕掛けたくないことがありますよね。新しい足が作成されてエントリー条件が変更されるまで、永遠と仕掛けてしまいますので。そんな時に役に立つのが1本の足で1回だけ仕掛ける機能です。

この機能を使うことで、こうした無駄な仕掛けを排除することが可能になります。

というわけで、1本の足で1回だけ仕掛ける機能を紹介します。意外とシンプルです。

まずは、extern変数に以下を追加します。

extern string Note02_9          = "--- entry only once per 1 bar --------------------------------";
extern bool   UseEntryPer1Bar   = true;

UseEntryPer1Barをtrueにすれば、この機能が有効になります。続いて、グローバル変数に以下を追加します。

// 1本の足で1回だけ仕掛ける
int    gPrvBars       = 0;

前回の値動き時の足(バー)の本数を格納しておくための変数です。そして、OnInit()に以下を追加します。

  gPrvBars = Bars;

BarsはMQL4の定義済み変数と呼ばれるもので、現在のチャートの足の本数を返してくれます。さらに、OnTick()の冒頭に以下を追加します。

  int currentBars = Bars;

また、仕掛けの前に、以下を追加します。これがキモになります。

  // -----------------------------------------------------------------
  // 仕掛けフィルター(1本の足で1回だけ仕掛ける)
  // -----------------------------------------------------------------
  if(UseEntryPer1Bar){
    // 新しい足を生成した時ではない場合は、仕掛けない
    if(currentBars == gPrvBars){
      gPrvBars = currentBars;
      return;
    }
  }

現在の足の本数と前回の足の本数を比較し、一致していれば新しい足は作成されていないと判断できるため、これ以上処理が進まないようにreturnしています。新しい足が作成された瞬間のOnTick()では、currentBarsがgPrvBarsより1だけ大きな値になります。だから一致しなくなるんですね。

最後に、OnTick()内でreturnを記述している直前に以下を追加して完成です。現在の足の本数を前回の足の本数として格納しています。

  gPrvBars = currentBars;

サンプルEA

五月雨の説明でイメージが沸きづらいと思いますので、サンプルEAを載せておきます。そろそろサンプルEAが膨大な量になってきましたね…。

//+------------------------------------------------------------------+
//|                                                       Sample.mq4 |
//|                                     Copyright (c) 2015, りゅーき |
//|                                            https://autofx100.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright (c) 2015, りゅーき"
#property link      "https://autofx100.com/"
#property version   "1.00"

//+------------------------------------------------------------------+
//| ライブラリ                                                       |
//+------------------------------------------------------------------+
#include <stderror.mqh>
#include <stdlib.mqh>
#include <WinUser32.mqh>

//+------------------------------------------------------------------+
//| インポート                                                       |
//+------------------------------------------------------------------+
// Windows API
#import "kernel32.dll"
  int GetTimeZoneInformation(int& tzinfo[]);
#import

//+------------------------------------------------------------------+
//| 定数定義                                                         |
//+------------------------------------------------------------------+
// 共通
#define MAX_RETRY_TIME   10.0 // 秒
#define SLEEP_TIME        0.1 // 秒
#define MILLISEC_2_SEC 1000.0 // ミリ秒

//+------------------------------------------------------------------+
//| EAパラメータ設定情報                                             |
//+------------------------------------------------------------------+
extern string Note01          = "=== General ==================================================";
extern int    MagicNumber     = 7777777;
extern int    SlippagePips    = 5;
extern double LotSize         = 0.01;
extern string Comments        = "";

extern string Note02          = "=== Entry ====================================================";
extern string Note02_1        = "--- entry only once per 1 bar --------------------------------";
extern bool   UseEntryPer1Bar = true;

extern string Note03          = "=== Exit =====================================================";
extern double InitialSL_Pips  = 50.0;

//+------------------------------------------------------------------+
//| グローバル変数                                                   |
//+------------------------------------------------------------------+
// 共通
double gPipsPoint     = 0.0;
int    gSlippage      = 0;
color  gArrowColor[6] = {Blue, Red, Blue, Red, Blue, Red}; //BUY: Blue, SELL: Red
// 1本の足で1回だけ仕掛ける
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;

  // -----------------------------------------------------------------
  // 仕掛けフィルター(1本の足で1回だけ仕掛ける)
  // -----------------------------------------------------------------
  if(UseEntryPer1Bar){
    // 新しい足を生成した時ではない場合は、仕掛けない
    if(currentBars == gPrvBars){
      gPrvBars = currentBars;
      return;
    }
  }

  // -----------------------------------------------------------------
  // 仕掛け
  // -----------------------------------------------------------------
  // 成行注文
  int ticket = orderSendReliableRange(Symbol(), OP_BUY, LotSize, Ask, gSlippage, InitialSL_Pips, 0.0, Comments, MagicNumber, 0, gArrowColor[OP_BUY]);

  // 本来はticketの値によって後続の処理を制御する必要があるが、簡単のため、ここでは無視

  gPrvBars = currentBars;
}

//+------------------------------------------------------------------+
//|【関数】信頼できる仕掛け注文(値幅指定)                          |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aSymbol            通貨ペア                      |
//|         ○      aCmd               注文種別                      |
//|         ○      aVolume            ロット数                      |
//|         ○      aPrice             仕掛け価格                    |
//|         ○      aSlippage          スリッページ(ポイント)      |
//|         ○      aStoploss          損切り価格                    |
//|         ○      aTakeprofit        利食い価格                    |
//|         △      aComment           コメント                      |
//|         △      aMagic             マジックナンバー              |
//|         △      aExpiration        待機注文の有効期限            |
//|         △      aArrow_color       チャート上の矢印の色          |
//|                                                                  |
//|【戻値】チケット番号(エラーの場合は、-1)                        |
//|                                                                  |
//|【備考】△:既定値あり                                            |
//+------------------------------------------------------------------+
int orderSendReliableRange(string aSymbol, int aCmd, double aVolume, double aPrice, int aSlippage, double aStoplossPips, double aTakeprofitPips, string aComment = NULL, int aMagic = 0, datetime aExpiration = 0, color aArrow_color = CLR_NONE)
{
  int plusMinusSign = 1;

  if(aCmd == OP_SELL || aCmd == OP_SELLLIMIT || aCmd == OP_SELLSTOP){
    plusMinusSign *= -1;
  }

  double sl = 0.0;
  double tp = 0.0;

  if(aStoplossPips > 0.0){
    sl = aPrice - aStoplossPips * gPipsPoint * plusMinusSign;
  }

  if(aTakeprofitPips > 0.0){
    tp = aPrice + aTakeprofitPips * gPipsPoint * plusMinusSign;
  }

  int result = orderSendReliable(aSymbol, aCmd, aVolume, aPrice, aSlippage, sl, tp, aComment, aMagic, aExpiration, aArrow_color);

  return(result);
}

//+------------------------------------------------------------------+
//|【関数】信頼できる仕掛け注文                                      |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aSymbol            通貨ペア                      |
//|         ○      aCmd               注文種別                      |
//|         ○      aVolume            ロット数                      |
//|         ○      aPrice             仕掛け価格                    |
//|         ○      aSlippage          スリッページ(ポイント)      |
//|         ○      aStoploss          損切り価格                    |
//|         ○      aTakeprofit        利食い価格                    |
//|         △      aComment           コメント                      |
//|         △      aMagic             マジックナンバー              |
//|         △      aExpiration        待機注文の有効期限            |
//|         △      aArrow_color       チャート上の矢印の色          |
//|                                                                  |
//|【戻値】チケット番号(エラーの場合は、-1)                        |
//|                                                                  |
//|【備考】△:既定値あり                                            |
//+------------------------------------------------------------------+
int orderSendReliable(string aSymbol, int aCmd, double aVolume, double aPrice, int aSlippage, double aStoploss, double aTakeprofit, string aComment = NULL, int aMagic = 0, datetime aExpiration = 0, color aArrow_color = CLR_NONE)
{
  int ticket = -1;

  int startTime = GetTickCount();

  Print("Attempted orderSendReliable(" + aSymbol + ", " + orderType2String(aCmd) + ", " + aVolume + "lots, " + aPrice + ", Slippage:" + aSlippage + ", SL:"+ aStoploss + ", TP:" + aTakeprofit + ", Comment:" + aComment + ", Magic:" + aMagic + ", Expiration:" + TimeToStr(aExpiration) + ", ArrowColor:" + aArrow_color + ")");

  double digits = MarketInfo(aSymbol, MODE_DIGITS);

  aStoploss   = NormalizeDouble(aStoploss,   digits);
  aTakeprofit = NormalizeDouble(aTakeprofit, digits);

  double stopLevel   = MarketInfo(aSymbol, MODE_STOPLEVEL) * MarketInfo(aSymbol, MODE_POINT);
  double freezeLevel = MarketInfo(aSymbol, MODE_FREEZELEVEL) * MarketInfo(aSymbol, MODE_POINT);

  while(true){
    if(IsStopped()){
      Print("Trading is stopped!");
      return(-1);
    }

    if(GetTickCount() - startTime > MAX_RETRY_TIME * MILLISEC_2_SEC){
      Print("Retry attempts maxed at " + MAX_RETRY_TIME + "sec");
      return(-1);
    }

    // MarketInfo関数でレートを取得しており、定義済変数であるAskとBidは未使用のため、不要のはずだけど、念のため
    RefreshRates();

    double ask = NormalizeDouble(MarketInfo(aSymbol, MODE_ASK), digits);
    double bid = NormalizeDouble(MarketInfo(aSymbol, MODE_BID), digits);

    if(aCmd == OP_BUY){
      aPrice = ask;
    }else if(aCmd == OP_SELL){
      aPrice = bid;
    }

    // 仕掛け/損切り/利食いがストップレベル未満かフリーズレベル以下の場合、エラー
    if(aCmd == OP_BUY){
      if(MathAbs(bid - aStoploss) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aTakeprofit - bid) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(bid - aStoploss) <= freezeLevel){
        Print("FreezeLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aTakeprofit - bid) <= freezeLevel){
        Print("FreezeLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }else if(aCmd == OP_SELL){
      if(MathAbs(aStoploss - ask) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(ask - aTakeprofit) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aStoploss - ask) <= freezeLevel){
        Print("FreezeLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(ask - aTakeprofit) <= freezeLevel){
        Print("FreezeLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }else if(aCmd == OP_BUYLIMIT){
      if(MathAbs(ask - aPrice) < stopLevel){
        Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - aStoploss) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aTakeprofit - aPrice) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(ask - aPrice) <= freezeLevel){
        Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }else if(aCmd == OP_SELLLIMIT){
      if(MathAbs(aPrice - bid) < stopLevel){
        Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aStoploss - aPrice) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - aTakeprofit) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - bid) <= freezeLevel){
        Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }else if(aCmd == OP_BUYSTOP){
      if(MathAbs(aPrice - ask) < stopLevel){
        Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - aStoploss) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aTakeprofit - aPrice) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - ask) <= freezeLevel){
        Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }else if(aCmd == OP_SELLSTOP){
      if(MathAbs(bid - aPrice) < stopLevel){
        Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aStoploss - aPrice) < stopLevel){
        Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(aPrice - aTakeprofit) < stopLevel){
        Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }else if(MathAbs(bid - aPrice) <= freezeLevel){
        Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")");
        return(-1);
      }
    }

    if(IsTradeContextBusy()){
      Print("Must wait for trade context");
    }else{
      ticket = OrderSend(aSymbol, aCmd, aVolume, aPrice, aSlippage, aStoploss, aTakeprofit, aComment, aMagic, aExpiration, aArrow_color);

      if(ticket > 0){
        Print("Success! Ticket #", ticket, " ", orderType2String(aCmd), " order placed, details follow");
        bool selected = OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES);
        OrderPrint();
        return(ticket);
      }

      int err = GetLastError();

      // 一時的エラーの場合はリトライするが、恒常的エラーの場合は処理中断(リトライしてもエラーになるため)
      if(err == ERR_NO_ERROR || 
         err == ERR_COMMON_ERROR ||
         err == ERR_SERVER_BUSY ||
         err == ERR_NO_CONNECTION ||
         err == ERR_TRADE_TIMEOUT ||
         err == ERR_INVALID_PRICE ||
         err == ERR_PRICE_CHANGED ||
         err == ERR_OFF_QUOTES ||
         err == ERR_BROKER_BUSY ||
         err == ERR_REQUOTE ||
         err == ERR_TRADE_CONTEXT_BUSY){
        Print("Temporary Error: " + err + " " + ErrorDescription(err) + ". waiting");
      }else{
        Print("Permanent Error: " + err + " " + ErrorDescription(err) + ". giving up");
        return(-1);
      }

      // 最適化とバックテスト時はリトライは不要
      if(IsOptimization() || IsTesting()){
        return(-1);
      }
    }

    Sleep(SLEEP_TIME * MILLISEC_2_SEC);
  }

  return(-1);
}

//+------------------------------------------------------------------+
//|【関数】注文種別の数値を文字列に変換する                          |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aType              注文種別                      |
//|                                                                  |
//|【戻値】注文種別の数値に対応する文字列                            |
//|                                                                  |
//|【備考】なし                                                      |
//+------------------------------------------------------------------+
string orderType2String(int aType)
{
  if(aType == OP_BUY){
    return("BUY");
  }else if(aType == OP_SELL){
    return("SELL");
  }else if(aType == OP_BUYSTOP){
    return("BUY STOP");
  }else if(aType == OP_SELLSTOP){
    return("SELL STOP");
  }else if(aType == OP_BUYLIMIT){
    return("BUY LIMIT");
  }else if(aType == OP_SELLLIMIT){
    return("SELL LIMIT");
  }else{
    return("None (" + aType + ")");
  }
}

//+------------------------------------------------------------------+
//|【関数】1pips当たりの価格単位を計算する                           |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aSymbol            通貨ペア                      |
//|                                                                  |
//|【戻値】1pips当たりの価格単位                                     |
//|                                                                  |
//|【備考】なし                                                      |
//+------------------------------------------------------------------+
double currencyUnitPerPips(string aSymbol)
{
  // 通貨ペアに対応する小数点数を取得
  double digits = MarketInfo(aSymbol, MODE_DIGITS);

  // 通貨ペアに対応するポイント(最小価格単位)を取得
  // 3桁/5桁のFX業者の場合、0.001/0.00001
  // 2桁/4桁のFX業者の場合、0.01/0.0001
  double point = MarketInfo(aSymbol, MODE_POINT);

  // 価格単位の初期化
  double currencyUnit = 0.0;

  // 3桁/5桁のFX業者の場合
  if(digits == 3.0 || digits == 5.0){
    currencyUnit = point * 10.0;
  // 2桁/4桁のFX業者の場合
  }else{
    currencyUnit = point;
  }

  return(currencyUnit);
}

//+------------------------------------------------------------------+
//|【関数】ポイント換算した許容スリッページを計算する                |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aSymbol            通貨ペア                      |
//|         ○      aSlippagePips      許容スリッページ(pips)      |
//|                                                                  |
//|【戻値】許容スリッページ(ポイント)                              |
//|                                                                  |
//|【備考】なし                                                      |
//+------------------------------------------------------------------+
int getSlippage(string aSymbol, int aSlippagePips)
{
  double digits = MarketInfo(aSymbol, MODE_DIGITS);
  int slippage = 0;

  // 3桁/5桁業者の場合
  if(digits == 3.0 || digits == 5.0){
    slippage = aSlippagePips * 10;
  // 2桁/4桁業者の場合
  }else{
    slippage = aSlippagePips;
  }

  return(slippage);
}
>完全放ったらかしEA 「AutoEndlessCatchRange」

完全放ったらかしEA 「AutoEndlessCatchRange」

「本業が忙しい!」「でも資産運用したい!」そんなあなたに最適なEAです。兼業トレーダーの方はチャートを毎日みて分析してトレードする時間はなかなか確保できないものです。トレードは本EAに任せて、本業やプライベートの時間をもっと増やしませんか?元々は自分自身のために開発したEAですので、手抜き無しのガチものです。

CTR IMG