標準偏差を用いた変動損切り幅

固定の損切り幅は為替相場の動きを無視している

多くのEAの損切り幅は固定になっています。が、これはいかがなものでしょうか。ボラティリティを完全無視ですよね。同じ通貨ペアでもボラティリティは低い時もあれば、高い時もあります。

仮に、損切り幅を50pipsに設定したとしましょう。ボラが高い時は、ランダム性(ノイズ)の影響で、相場が転換していないのに損切りラインに引っかかってしまう可能性がありますし、逆にボラが低い時は、相場の転換地点よりずっと遠い位置に損切りラインを置くことになりかねません。

これでは悪戯に損失が大きくなるだけです。損切り幅はボラの高低で変動させる方が望ましいはずです。

とはいえ、ロット数を固定にして損切りラインを変動させてしまうと、ボラが高い時は損失額が大きくなってしまいます(損切り幅が広くなりますので)。

従って、損切り幅が広くなる場合はロット数を減らし、損切り幅が狭くなる場合はロット数を増やせば、損失額を常に一定にすることができます。

ボラの高低を計測する代表的な指標にATRがありますが、今回は標準偏差を用いた変動損切り幅の方法をご紹介します。なお、標準偏差の意味の説明は割愛します。

意外とシンプルです。直接、サンプル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>
#include <Original/Basic.mqh>
#include <Original/DateAndTime.mqh>
#include <Original/LotSizing.mqh>
#include <Original/OrderHandle.mqh>
#include <Original/OrderReliable.mqh>

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

extern string Note02                = "=== Entry ====================================================";
extern string Note02_1              = "--- entry only once per 1 bar --------------------------------";
extern bool   UseEntryPer1Bar       = true;
extern string Note02_2              = "--- Risk % lot -----------------------------------------------";
extern bool   UseVariableLotSizeFlg = true;
extern double FixLotSize            = 0.01;
extern double RiskPercent           = 2.0;

extern string Note03                = "=== Exit =====================================================";
extern int    SD_TimeFrame          = PERIOD_D1;
extern int    SD_Period             = 25;
extern int    SD_SIGMA              = 3; // σ

//+------------------------------------------------------------------+
//| グローバル変数                                                   |
//+------------------------------------------------------------------+
// 共通
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;

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

  // -----------------------------------------------------------------
  // 仕掛け
  // -----------------------------------------------------------------
  if(UseVariableLotSizeFlg){
    // 標準偏差
    double SD = iStdDev(NULL, SD_TimeFrame, SD_Period, 0, MODE_SMA, PRICE_CLOSE, 1);

    // 標準偏差に基づく変動損切り幅
    double slRange = NormalizeDouble(SD_SIGMA * SD, MarketInfo(Symbol(), MODE_DIGITS));

    double lotSize = calcLotSizeRiskPercent(AccountBalance(), Symbol(), slRange / gPipsPoint, RiskPercent);
  }else{
    lotSize = FixLotSize;
  }

  // 成行注文
  int ticket = orderSendReliable(Symbol(), OP_BUY, lotSize, Ask, gSlippage, Ask - slRange, 0.0, Comments, MagicNumber, 0, gArrowColor[OP_BUY]);

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

  gPrvBars = currentBars;
}

1本の足で1回だけ仕掛ける機能を盛り込んでいますが、仕掛けを間引きたかっただけですので、無視いただいて結構です。

標準偏差に基づく変動損切り幅を実現しているのは以下の2行のみです。

    // 標準偏差
    double SD = iStdDev(NULL, SD_TimeFrame, SD_Period, 0, MODE_SMA, PRICE_CLOSE, 1);

    // 標準偏差に基づく変動損切り幅
    double slRange = NormalizeDouble(SD_SIGMA * SD, MarketInfo(Symbol(), MODE_DIGITS));

iStdDev()関数はMQL4の標準関数で、標準偏差を計算してくれます。また、SD_SIGMAは1σ、2σ、3σの数値部分を表しています。ちなみに標準偏差の値は値幅です。

変動損切り幅さえ計算できれば、後はcalcLotSizeRiskPercent()関数に投入してあげれば常にリスクを一定にしたロット数を得られます。関数の詳細は、資産のN%のリスクのロット数を計算する機能をご参照ください。

MT4の無料プログラミング講座

LINE公式アカウントを友だち追加して、MT4のプログラミング講座を無料で受けちゃおう!

超豪華プレゼントも盛りだくさん♪

MT4プログラミングを習得すると、オリジナルEA運用、作成代行、商品販売等、複数の収入源を手に入れられるよ。副業に最適だね!

↓↓↓ 詳細はこちら ↓↓↓

アイキャッチ

>

エターナル・パートナーPRO ~MT4裁量トレード支援ツール~ 「MT4は裁量トレーダーに優しくない」そう思ったことありませんか?もっと快適にトレードするための強力な売買ツールが必要だと考え、開発したのが「エターナル・パートナーPRO」です。元々は自分自身のために開発したツールですので、手抜き無しのガチものです。既に200名近い方に手に取っていただき、喜びの声が続々と届いております。ぜひご覧ください!

CTR IMG