固定の損切り幅は為替相場の動きを無視している
多くの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%のリスクのロット数を計算する機能をご参照ください。