English Русский 中文 Español Deutsch Português
preview
オプションを使わないオプション取引(第2回):実取引への適用

オプションを使わないオプション取引(第2回):実取引への適用

MetaTrader 5 |
22 8
Dmitriy Skub
Dmitriy Skub

はじめに

本連載第1回では、オプション取引という金融商品について簡単に説明し、その可能性、メリット、デメリットについて解説しました。また、原資産を使ってオプションを再現(エミュレーション)する方法について理論を構築し、それをMQL5で実際に実装しました。今回は、実際の市場取引においてオプションを運用してみます。 

そのために、オプションのエミュレーションによって算出された水準を、原資産に対する実際の注文・ポジションへ変換し、その結果として形成される総ポジションを継続的にリバランスするEAを作成します。


実際の取引で使用する

まず、取引でどのような戦略を使用できるのかを見てみましょう。ここでは、投機的な戦略のみを扱います。最も単純なものから始めます。それは、単一オプションの買い・売りです。そのため、考えられる基本的なオプションの種類を整理して見ていきます。

シンプルな取引戦略とその利用条件

ロングコール

  • アイデア:コールオプションを買う 
  • 条件:原資産価格の上昇に確信がある場合
  • 利益:無制限
  • リスク:オプションの支払プレミアム (エミュレーションではプレミアムは存在しない)

ロングプット

  • アイデア:原資産価格の下落を見越してプットオプションを買う
  • 条件:原資産価格の下落に確信がある場合
  • 利益:無制限
  • リスク:オプションの支払プレミアム (エミュレーションではプレミアムは存在しない)

ショートコール

  • アイデア:原資産価格が上昇しないと予想してコールオプションを売る。必ずしも価格が下落する必要はない
  • 条件:原資産が上昇しないと確信している場合
  • 利益:オプション買い手から受け取るプレミアム (ただし、エミュレーションモデルにはプレミアムが存在しない)
  • リスク:制限なし

ショートプット

  • アイデア:原資産価格が下落しないと予想してプットオプションを売る。必ずしも価格が上昇する必要はない
  • 条件:原資産が下落しないと確信している場合
  • 利益:オプション買い手から受け取るプレミアム (ただし、エミュレーションモデルにはプレミアムが存在しない)
  • リスク:無制限

注記:

  • エミュレーションされた単一オプションを売ることには、あまり意味がありません。これは、実際のオプション取引とは異なり、プレミアムを受け取れないためです。しかし、後でより複雑なオプション構成(株式市場でいうオプションポートフォリオ)を作成するためには、すべての種類のオプションを実装する必要があります。
  • エミュレーションされた単一オプションを買う場合、当然ながらプレミアムを支払う必要はありません。しかし、ポートフォリオをリバランスする際には、一定の損失が蓄積される可能性があります。その損失は、オプションを購入する際に支払うプレミアムに相当するものと考えることができます。その金額は、原資産価格がどの程度変化したか、そしてポジションをどのくらいの期間保有したかによって決まります。一般に、この損失はプレミアムに匹敵する水準になります。


取引戦略を実装するEAを開発する

TOptionBase基底クラスおよびOptionLongCall、OptionLongPut、OptionShortCall、OptionShortPutの各オプションクラスは、変更せずにそのまま使用します。これらのクラスについては、前回の記事ですでに説明しています。ここで新たに、オプション構成の基底クラスを追加します。このクラスを使用することで、後ほど任意の複雑さを持つオプション構成を作成できるようになります。

このTOptionConstructionBaseクラスを以下に示します。今回のTOptionConstructionBaseクラスは、MQL5標準ライブラリに含まれているCList標準クラスを継承しています。CListにアクセスするためには、ファイルの先頭に以下の行を追加する必要があります

#include    <Arrays\List.mqh>

これにより、オプションのリストを操作し、ポートフォリオ全体の必要な集計特性を取得することができます。それでは、オプション構成クラスを見てみましょう。

// =====================================================================
//  Base class of the option construction - derived from 'CList':
// =====================================================================
class TOptionConstructionBase : public CList
{
protected:
  ENUM_OPTION_CONSTRUCTION    type_enum;
  double    total_delta;
  bool      is_option_construction_inited_Flag;

public:
  // ---------------------------------------------------------------------
  //  Destructor:
  // ---------------------------------------------------------------------
  ~TOptionConstructionBase()
  {
    this.Clear();
  }
  // ---------------------------------------------------------------------
  //  Constructor:
  // ---------------------------------------------------------------------
  TOptionConstructionBase(ENUM_OPTION_CONSTRUCTION _type_enum)
  :
  type_enum(_type_enum),
  total_delta(0.0),
  is_option_construction_inited_Flag(false),
  CList()
  {
    this.FreeMode(true);
  }
  // ---------------------------------------------------------------------
  //  Get the value of the previously calculated normalized delta:
  // ---------------------------------------------------------------------
  double GetOptionConstructionDelta()
  {
    return(this.total_delta);
  }
  // ---------------------------------------------------------------------
  //  Get the value of the general initialization flag of the option construction:
  // ---------------------------------------------------------------------
  bool IsOptionConstructionInited()
  {
    return(this.is_option_construction_inited_Flag);
  }
  // ---------------------------------------------------------------------
  //  Set the delta normalization range for the central strike:
  // ---------------------------------------------------------------------
  void SetOptionConstructionRange(const double& _strike[], const double& _norm_price[])
  {
    this.is_option_construction_inited_Flag = true;
    if(this.Total() > 0)
    {
      int    i = 0;
      TOptionBase* curr_option = this.GetFirstNode();
      while(curr_option != NULL)
      {
        curr_option.SetRange(_strike[i], _norm_price[i]);
        if(curr_option.IsRangeInited() == true)
        {
          this.is_option_construction_inited_Flag = this.is_option_construction_inited_Flag && true;
        }
        else
        {
          this.is_option_construction_inited_Flag = false;
        }
        curr_option = this.GetNextNode();
        i++;
      }
    }
  }
  // ---------------------------------------------------------------------
  //  Delta update iterator:
  // ---------------------------------------------------------------------
  double UpdateOptionConstructionDelta(const double _price)
  {
    this.total_delta = 0.0;
    if(this.Total() > 0)
    {
      TOptionBase* curr_option = this.GetFirstNode();
      while(curr_option != NULL)
      {
        this.total_delta += curr_option.UpdateDelta(_price);
        curr_option = this.GetNextNode();
      }
    }

    return(this.total_delta);
  }
  // ---------------------------------------------------------------------
  //  Create an option construction:
  // ---------------------------------------------------------------------
  virtual void CreateOptionConstruction(const double _k, const double _s, const int _digits) = 0;
};
// ---------------------------------------------------------------------

詳しく見てみましょう。ご覧のように、提示したコードの一番下には、CreateOptionConstruction抽象メソッドの宣言があります。そのため、基底クラス自体が抽象クラスとなっています。このメソッドは、オプション構成を生成する役割を担っており、派生クラスで定義されます。メソッドには_k、_s、_digitsというパラメータが渡されます。最初の2つは、オプションをエミュレートするシグモイド関数におけるKとSの値です。最後の_digitsは、原資産の小数点以下の桁数を表します。

また、オプション構成の種類を指定するために、ENUM_OPTION_CONSTRUCTIONという列挙型も実装しました。現段階では、次のようになっています。

// ---------------------------------------------------------------------
//  Option construction:
// ---------------------------------------------------------------------
enum ENUM_OPTION_CONSTRUCTION
{
  ENUM_OPTION_CONSTRUCTION_RISING = 0,                                // Base Active Rising - Long CALL
  ENUM_OPTION_CONSTRUCTION_FALLING = 1,                               // Base Active Falling - Long PUT
  ENUM_OPTION_CONSTRUCTION_NOT_RISING = 2,                            // Base Active NOT Rising - Short CALL
  ENUM_OPTION_CONSTRUCTION_NOT_FALLING = 3,                           // Base Active NOT Falling - Short PUT
};
// ---------------------------------------------------------------------

将来的には、さらに複雑なオプション構成や新しいタイプを列挙型に追加していく予定です。このタイプは、オブジェクトを生成する際に、クラスのコンストラクタへパラメータとして渡されます。

SetOptionConstructionRange (const double& _strike[], const double& _norm_price[])を使用すると、オプション構成に含まれる各オプションについて、中心となるストライク価格に対するデルタの正規化範囲を設定できます。ストライク価格と正規化範囲の値は、それぞれ対応する値を格納した配列への参照として渡されます。これらの配列のサイズは、オプション構成に含まれるオプションの数と同じである必要があります。

上記のオプション構成では、配列のサイズは常に1です。今回のテスト用コードでは配列サイズをチェックしていませんが、実際の取引で使用するバージョンでは、このチェックを簡単に追加できます。オプション構成は最初に指定されるため、配列のサイズ、つまり含まれるオプションの数はあらかじめ分かっているからです。

また、基底クラスにはUpdateOptionConstructionDelta(const double _price)も定義されています。このメソッドは、オプション構成全体のデルタを更新し、計算された合計デルタを返します。メソッドの入力パラメータは原資産の価格です。このメソッドでは、CListクラスのメソッドを使用して、リストに含まれるすべての要素を順番に処理します。

次に、実際のオプション構成を基底クラスから派生させます。すべての機能は基底クラスに実装されているため、派生クラスは非常にシンプルな形になります。

// =====================================================================
//  Class of option construction of 'Base Active Rising' type:
// =====================================================================
class BaseActiveRisingOptionConstruction : public TOptionConstructionBase
{
public:
  // ---------------------------------------------------------------------
  //  Constructor:
  // ---------------------------------------------------------------------
  BaseActiveRisingOptionConstruction()
  :
  TOptionConstructionBase(ENUM_OPTION_CONSTRUCTION_RISING)
  {
  }
  // ---------------------------------------------------------------------
  //  Create an option construction:
  // ---------------------------------------------------------------------
  virtual void    CreateOptionConstruction(const double _k, const double _s, const int _digits) override
  {
    this.Add(new OptionLongCall(_k, _s, _digits));
  }
};

// =====================================================================
//  Class of option construction of 'Base Active Falling' type:
// =====================================================================
class BaseActiveFallingOptionConstruction : public TOptionConstructionBase
{
public:
  // ---------------------------------------------------------------------
  //  Constructor:
  // ---------------------------------------------------------------------
  BaseActiveFallingOptionConstruction()
  :
  TOptionConstructionBase(ENUM_OPTION_CONSTRUCTION_FALLING)
  {
  }
  // ---------------------------------------------------------------------
  //  Create an option construction:
  // ---------------------------------------------------------------------
  virtual void    CreateOptionConstruction(const double _k, const double _s, const int _digits) override
  {
    this.Add(new OptionLongPut(_k, _s, _digits));
  }
};

// =====================================================================
//  Class of option construction of 'Base Active NOT Rising' type:
// =====================================================================
class BaseActiveNotRisingOptionConstruction : public TOptionConstructionBase
{
public:
  // ---------------------------------------------------------------------
  //  Constructor:
  // ---------------------------------------------------------------------
  BaseActiveNotRisingOptionConstruction()
  :
  TOptionConstructionBase(ENUM_OPTION_CONSTRUCTION_NOT_RISING)
  {
  }
  // ---------------------------------------------------------------------
  //  Create an option construction:
  // ---------------------------------------------------------------------
  virtual void    CreateOptionConstruction(const double _k, const double _s, const int _digits) override
  {
    this.Add(new OptionShortCall(_k, _s, _digits));
  }
};

// =====================================================================
//  Class of option construction of 'Base Active NOT Falling' type:
// =====================================================================
class BaseActiveNotFallingOptionConstruction : public TOptionConstructionBase
{
public:
  // ---------------------------------------------------------------------
  //  Constructor:
  // ---------------------------------------------------------------------
  BaseActiveNotFallingOptionConstruction()
  :
  TOptionConstructionBase(ENUM_OPTION_CONSTRUCTION_NOT_FALLING)
  {
  }
  // ---------------------------------------------------------------------
  //  Create an option construction:
  // ---------------------------------------------------------------------
  virtual void    CreateOptionConstruction(const double _k, const double _s, const int _digits) override
  {
    this.Add(new OptionShortPut(_k, _s, _digits));
  }
};

// ---------------------------------------------------------------------

派生クラスでする必要があるのは、CreateOptionConstructionオプション構成メソッドを定義することだけです。このメソッドでは、必要なオプション(またはオプションのグループ)のオブジェクトを生成し、CList::Addメソッドを呼び出して、生成したオブジェクトをリストに追加します。

これらのクラスは、この記事に添付されているOptionEmulatorA2.mqhファイルに収録されています。

トレーダー設定項目

それでは次に、実際のポジション管理を使用したエミュレーション用EA(エキスパートアドバイザー)の実装に進みましょう。まず、EA全体の状態、つまり取引状態を定義する列挙型を追加します。

// ---------------------------------------------------------------------
//  Current trading status:
// ---------------------------------------------------------------------
enum ENUM_TRADE_MODE_STATE
{
  ENUM_TRADE_MODE_STARTED,                                            // trading is ONGOING, positions are HANDLED
  ENUM_TRADE_MODE_STOPPED,                                            // trading is STOPPED, all positions are CLOSED
  ENUM_TRADE_MODE_PAUSED,                                             // trading is SUSPENDED by the operator, existing positions are NOT HANDLED
  ENUM_TRADE_MODE_WAITING,                                            // trading is AWAITING automatic renewal, existing positions are HANDLED, IF POSSIBLE
};
// ---------------------------------------------------------------------

EAの初期バージョンでは、状態は2種類だけ使用します。すなわち、取引停止中と取引実行中です。EAは初期化が完了して起動すると取引を開始し、設定した有効期限に到達すると取引を停止します。ここでは、新しい日の開始前に必ず満期を迎える日次オプションを使用します。 

次に、EAに必要な外部パラメータを追加します。

// =====================================================================
//  Externally set parameters:
// =====================================================================
input ENUM_OPTION_CONSTRUCTION    OptionConstruction = ENUM_OPTION_CONSTRUCTION_RISING;  // Option Construction
input ulong     BaseMagic = 10000UL;                                  // Base Magic
input int       MinLotsMultiplier = 1;                                // Min Lots Multiplier
// ---------------------------------------------------------------------
input int       AddNewFromHours = 0;                                  // Add New Hours (0...23) From
input int       AddNewToHours = 24;                                   // Add New Hours (1...24) To
input int       ExpirationTimeHours = 24;                             // Expiration Time, Hours (1...24)
input int       ExpirationTimeMinutes = 0;                            // Expiration Time, Minutes (0...59)
// ---------------------------------------------------------------------
input double    ZeroDelta = 0.01;                                     // Zero Delta (0.01...0.1)
input string    ForceAutoExpirationTime = "23:50";                    // Force Auto Expiration Time (MT5 Server)
input int       ADRDaysNumber = 20;                                   // ADR Days Number
// ---------------------------------------------------------------------

外部パラメータのうち、いくつか分かりにくいものについて説明します。

  • BaseMagic:「マジックナンバー」の基準値です。ポジションを建てる際には、これにオプション・エミュレーションのレベル番号を100倍した値を加算します。
  • MinLotsMultiplier:各レベルでポジション数量を決定する際に使用する、最小ロットの倍率です。
  • AddNewFromHours:その日のEAの稼働開始時刻を、0~23時間で指定します。
  • AddNewToHours:その日のEAの稼働終了時刻を、1~24時間で指定します。
  • ExpirationTimeHours:オプション構成の1日あたりの満期時刻を、1~24時間で指定します。
  • ExpirationTimeMinutes:オプション構成の満期時刻の「分」を、0~59分で指定します。
  • ForceAutoExpirationTime:EAを強制的に満期とし、停止させる時刻を、hh:mm形式で指定します。
  • ADRDaysNumber:HV(ヒストリカルボラティリティ)を計算するために使用する計算に用いる過去日数です。

取引EA

ここでは、取引EAの以下の関数について詳しく見ていきます。

//---------------------------------------------------------------------
//    Get normalized trading volume:
//---------------------------------------------------------------------
//  • the required lot at the input;
//  • normalized lot at the output;
//---------------------------------------------------------------------
double
NormalizeLots(const double _requied_lots)
{
  double    lots, koeff;
  int       nmbr;

  if(min_trade_volume_step > 0.0)
  {
    koeff = 1.0 / min_trade_volume_step;
    nmbr = (int)MathLog10(koeff);
  }
  else
  {
    koeff = 1.0 / min_trade_volume;
    nmbr = 2;
  }
  lots = MathFloor(_requied_lots * koeff) / koeff;

  //  Lot limit from below:
  if(lots < min_trade_volume)
  {
    lots = min_trade_volume;
  }

  //  Upper lot limit:
  if(lots > max_trade_volume)
  {
    lots = max_trade_volume;
  }

  lots = NormalizeDouble(lots, nmbr);
  return(lots);
}

ロット数の正規化が必要なのは、実際の取引では、取引数量が連続的な値ではなく、一定の刻み幅で変化するためです。また、ロット数を表す小数点以下の桁数や、設定可能な最小・最大取引数量にも制限があります。上記で示したNormalizeLots関数では、これらの条件がすべて考慮されています。

// ---------------------------------------------------------------------
//    Normalize price considering the step of quote change:
// ---------------------------------------------------------------------
double
NormalizePrice(const double _price)
{
  //  Minimum step of change of quotes in points:
  double    min_price_step = NormalizeDouble(symbol_tick_size / Point(), 0 );

  double    norm_price = NormalizeDouble(NormalizeDouble((NormalizeDouble(_price / Point(), 0 )) / min_price_step, 0 ) * min_price_step * Point(), Digits());
  return(norm_price);
}
// ---------------------------------------------------------------------

ここでは、初期化時に取得したグローバル変数の値が使用されます。

double  min_trade_volume = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
double  max_trade_volume = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
double  min_trade_volume_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
double  symbol_tick_size = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE);

EAのアルゴリズムはOnTickで新しいティックを処理することに基づいています。簡略化されたハンドラ構造を以下に示します。

//    Handle a new tick (if all necessary conditions are met):
if(is_bars_loaded_Flag == true && is_adr_levels_calculated_Flag == true && option_construstion_Ptr.IsOptionConstructionInited() == true)
{
  if(SymbolInfoTick(Symbol(), tick) == true)
  {
    ask_option_construction_delta = option_construstion_Ptr.UpdateOptionConstructionDelta(tick.ask);
    bid_option_construction_delta = option_construstion_Ptr.UpdateOptionConstructionDelta(tick.bid);
    curr_option_construction_delta = option_construstion_Ptr.UpdateOptionConstructionDelta((tick.ask + tick.bid) / 2.0);

    if(is_first_ea_starting == true)
    {
      is_first_ea_starting = false;
Print("CurrDelta : ", DoubleToString(curr_option_construction_delta, 3), "  BidDelta : ", DoubleToString(bid_option_construction_delta, 3), "  AskDelta : ", DoubleToString(ask_option_construction_delta, 3));
    }

    //  Calculate the current REQUIRED POSITION VOLUME with a check to see if the option emulation level has changed:
    if(option_contruction_volume_Ptr.UpdateOptionLevel(curr_option_construction_delta, prev_option_level_value) == true)
    {
      //  Current sign of the option emulation level (+1/0/-1):
      live_option_level_sign = option_contruction_volume_Ptr.GetOptionLevelSign();
                
      //  Current value (modulo) of the option emulation level (0/1/2/3/4/5/6/7/8/9/10):
      live_option_level_value = option_contruction_volume_Ptr.GetOptionLevel();

      //  It is necessary to change the position volume - rebalance the option construction:
      if(live_option_level_value > 0)
      {
        live_position_lots_abs = NormalizeLots(live_option_level_value * min_trade_volume_step * MinLotsMultiplier);
      }
      else
      {
        live_position_lots_abs = 0.0;
      }

Print("#NEW LEVEL  Position Volume : ", DoubleToString(live_option_level_value * live_option_level_sign * MinLotsMultiplier, 1), "  CurrDelta : ", DoubleToString(curr_option_construction_delta, 3), "  Levels Prev/Live: ", prev_option_level_value, "/", live_option_level_value);

      //  If we are in 'STARTED' mode, adjust the total volume of virtual and real positions:
      if(current_trade_mode_state == ENUM_TRADE_MODE_STARTED)
      {
        //  If the value of the option emulation LEVEL has INCREASED, then positions need to be added to new levels:
        if(live_option_level_value > prev_option_level_value)
        {
          //  BUY positions:
          if(live_option_level_sign == 1)
          {
            //  If the interval for placing new orders has not yet passed:
            if(CheckAddingNew(tick.time) == true)
            {
              //  Set real orders at new levels:
              OpenBuyLevels(live_option_level_value, live_option_level_value - prev_option_level_value);
            }
          }
          //  SELL positions:
          else if(live_option_level_sign == -1)
          {
            //  If trading is allowed:
            if(is_trade_allowed_Flag == true)
            {
              //  If the interval for placing new orders has not yet passed:
              if(CheckAddingNew(tick.time) == true)
              {
                //  Set real orders at new levels:
                OpenSellLevels(live_option_level_value, live_option_level_value - prev_option_level_value);
              }
            }
          }
          prev_option_level_value = live_option_level_value;
          prev_option_level_sign = live_option_level_sign;
        }
        //  If the value of the option emulation LEVEL has DECREASED, then it is necessary to close some or all positions at the previous levels:
        else if(live_option_level_value < prev_option_level_value)
        {
          //  BUY positions:
          if(live_option_level_sign == 1)
          {
            //  If trading is allowed:
            if(is_trade_allowed_Flag == true)
            {
              for(int curr_level = prev_option_level_value; curr_level > live_option_level_value; curr_level--)
              {
                CloseLevelPositions(Symbol(), POSITION_TYPE_BUY, curr_level);
              }
            }
          }
          //  SELL positions:
          else if(live_option_level_sign == -1)
          {
            //  If trading is allowed:
            if(is_trade_allowed_Flag == true)
            {
              for(int curr_level = prev_option_level_value; curr_level > live_option_level_value; curr_level--)
              {
                CloseLevelPositions(Symbol(), POSITION_TYPE_SELL, curr_level);
              }
            }
          }
          //  The current value (modulo) of the delta level during option emulation has become ZERO (all positions should be closed):
          else  if(live_option_level_sign == 0)
          {
            //  If trading is allowed:
            if(is_trade_allowed_Flag == true)
            {
              if(prev_option_level_sign == 1)
              {
                for(int curr_level = prev_option_level_value; curr_level > live_option_level_value; curr_level--)
                {
                  CloseLevelPositions(Symbol(), POSITION_TYPE_BUY, curr_level);
                }
              }
              else if(prev_option_level_sign == -1)
              {
                for(int curr_level = prev_option_level_value; curr_level > live_option_level_value; curr_level--)
                {
                  CloseLevelPositions(Symbol(), POSITION_TYPE_SELL, curr_level);
                }
              }
            }
            live_position_lots_abs = 0.0;
            live_option_level_sign = 0;
          }
        }
      }
      prev_option_level_value = live_option_level_value;
      prev_option_level_sign = live_option_level_sign;      }
    }
  }
}

UpdateOptionLevelメソッドを呼び出して、オプションエミュレーションレベルの変化を監視します。レベルが変化した場合、このメソッドはtrueを返します。ここでは、現在のオプションエミュレーションレベルと、前回のティック時点でのレベルを比較します。

ポジションのリバランスが必要な場合は、オプションエミュレーションレベルが増加したのか、減少したのかを確認します。レベルが増加した場合は、ポジションを追加する必要があります。反対に、レベルが減少した場合は、一部のポジションを決済する必要があります。エミュレーションレベルがゼロになった場合は、保有しているすべてのポジションを決済します。このようにして、全体のポジションがリバランスされます。

なお、オプション構成の現在のデルタを計算する際の価格として、BidとAskの平均値を使用しています。これにより、デルタの変化がスプレッドの変動に左右される影響を軽減できます。EAの完全なコードは、この記事に添付されているファイルから確認できます。

ポジションの新規建てと決済には、成行注文を使用しています。これは、EAの動作検証を簡単にするためです(注文が約定することが保証されるためです)。今後は、新規ポジションの建てに指値注文へ切り替えることが推奨されており、実装も予定されています。これにより、スプレッドをエントリー時に支払う必要がなくなるため、手数料コストを削減し、取引結果を改善できます。

エミュレーションとリアルタイム取引のテスト

ここでは、EURUSDの価格が1日の間に主として上昇すると判断したとします。この場合、オプション構成のタイプをOptionConstruction = ENUM_OPTION_CONSTRUCTION_RISINGに設定します。以下の図は、Base Active Rising - Long CALLオプション構成をEAでエミュレーションした例です。図1は1日の開始時点からの全体像、図2は取引部分を拡大したものです。エミュレーションレベル1~9が作動しました。また、EAの稼働開始時にレベルのリバランスがおこなわれました。

図1:Base Active Rising - Long CALLオプション構成の動作例(全体像)

図2:Base Active Rising - Long CALLオプション構成の動作例(取引部分の拡大図)


図3:Base Active Rising - Long CALLオプション構成をエミュレーションしている際の現在のポジション状況

 

図4: オプション構成のエミュレーションにおけるリバランス結果(取引履歴に記録された取引)

次に、翌日になって、今度は価格が反転して下落すると判断したとします。この場合、 OptionConstructionのオプション構成をENUM_OPTION_CONSTRUCTION_FALLINGに設定します。しかし今回は運が悪く、1日の終わりまでに価格が予想とは逆方向に動いたため、損失が発生しました。図5は、このオプション構成の推移を示しています。エミュレーションレベル1~5が有効になり、リバランスによって発生した記録上の損失は-5.77米ドルでした(図6参照)。

図5:Base Active Rising - Long Putオプション構成の動作例(全体像)


図6: Base Active Rising - Long Putオプション構成のエミュレーションにおけるリバランス結果(取引履歴に記録された取引)

ポジションの最大合計取引数量は、0.1ロットに達する可能性があります。これは、最小ロット倍率が1の場合、10レベル × 0.01ロット = 0.1ロットとなるためです。図4から分かるように、最初のケースではオプション構成のリバランスによって-2.39米ドルの固定的な損失が発生し、2番目のケースでは-5.77米ドルの損失が発生しました(図6参照)。これは、オプションを購入する際に支払うプレミアムに相当するものと考えることができます。EAのパラメータ「ForceAutoExpirationTime = "23:50"」で指定されているとおり、23:50になるとオプション構成が満期を迎えます。最初のケースでは、この時点で利益が確定しました。もちろん、実際の取引結果は、その時の市場状況とトレーダーの判断・行動によって変わります。


結論

今回は、指定したオプション構成をエミュレーションするEAの実践的な実装について検討しました。そして、その実際の動作が、本連載第1回の記事で示した理論的な原則と一致することを確認しました。次回の記事では、実際の実用価値を持つオプション戦略の実装について見ていきます。これらは、プロのオプショントレーダーによって実際に利用されている戦略です。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/18363

添付されたファイル |
最後のコメント | ディスカッションに移動 (8)
prostotrader
prostotrader | 19 10月 2025 において 08:45

こんにちは!

もちろん、それは興味深いですね。

でも!

あなた:

-->仮に、EUR/USDの価格が日中に主に 上昇傾向で推移すると判断したとしましょう……

--->さて、翌日、価格が反転して下落すると判断したとしましょう……

またしても「コイン投げ」のような状況になり、最終的には必然的に証拠金を失うことにつながります。

ドミトリーさん、あなたは大変な努力をされましたが、それだけでは安定した収益にはつながりません。

追記

私は以前、ある実験を行いました。

M1ローソク足の1年間を取り上げ、最初はローソク足の始値で買い、引け値で売るという取引を1年間続けました。

その結果、大きな損失が出てしまいました。

その後、買いを売りに、売りを買いに変えて、また1年間続けてみました。そして……

またしても大きな損失を出しました! :)

追記

MOEXの全銘柄の先物によるヘッジポートフォリオ取引。

リスク +85/-15 %

マイナス15%というのは、予期せず配当が発表される可能性があるためです

9日前

今日

-15%を挽回するために懸命に働いている

Dmitriy Skub
Dmitriy Skub | 19 10月 2025 において 09:44

つまり、安定した収益を保証する市場戦略なんて存在しないんだ。あなたの戦略も例外じゃないし、ましてや「明日何が起こるかわからない」という現代の状況下ではなおさらだ。だから、ポジションを翌日に持ち越さずに、日中にだけ利益を稼ぐのが精一杯だと思うよ。あくまで私の個人的な意見だけどね。

あなたの場合、HFTでは主に株式とそれに対応する先物のペアから利益を得ている、という理解で合っていますか?

prostotrader
prostotrader | 19 10月 2025 において 09:50
Dmitriy Skub #:

つまり、安定した収益を保証する市場戦略なんてないんだ。あなたの戦略も例外じゃないし、ましてや、明日何が起こるかわからない現代の状況下ではなおさらだ。だから、持ち越さずにその日のうちに取引して、なんとか利益を出すしかないと思うよ。あくまで私の個人的な意見だけど。

あなたの場合、HFTでの主な利益は、株式とその先物のペアから得ている、という理解で合っていますか?

いいえ、フィナムが購入した株式に対して割引を適用してくれないため、私は現在、この「黄金の」100%利益が出る戦略は 使用していません。

現在は、MOEX上場のあらゆる株式を網羅したヘッジ用ポートフォリオの 先物取引のみを行っています。

--->つまり、安定した収益を保証する市場戦略など存在しないのです。

ただ、あなたがまだそれらを知らないだけなのです……

私を含め、誰もあなたにそのことを教えてはくれません。

追加

どのようなヘッジ戦略であれ、安定した利益をもたらさなければなりません。

重要な5つの要素

1. リスク

2. 適切な実施

3. 売買注文の執行速度

4. トレーダーの欲(年率50%で満足する人もいれば、500%でも物足りない人もいる――これこそが、99%のトレーダーが損失を出す原因なのだ……)

5. ロボットのみによる取引(人的要因は完全に排除されなければならない)
Dmitriy Skub
Dmitriy Skub | 19 10月 2025 において 12:36

ここで知っておくべきことは?

株式と先物の(統計的な意味での)最大の発散を待ち、そのタイミングで株式を購入し、先物を売却します。そして満期を待ちます。十分な資本があれば、十分に有効な戦略です。ただし、この戦略にもリスクはあります。

以前は、1日(あるいは数日)の間に乖離や収束を利用して売買を行い、場合によっては片方のポジションのみを決済していたかもしれません。

なぜ今はそうしないのかといえば、おそらく流動性が不足しているからでしょう。

Sergey Chalyshev
Sergey Chalyshev | 19 10月 2025 において 21:06

オプションやオプション戦略そのものは、それだけでは利益をもたらしません。これはFXと同様に、勝率は50%です。数学的な仕組みも同じで、正規分布に従います

オプションが(リスクのない)利益をもたらすのは、先物や株式と組み合わせて利用した場合に限られます。

MQL5での量子ニューラルネットワーク(第2回):ALGLIBのマルコフ行列を用いたバックプロパゲーション学習 MQL5での量子ニューラルネットワーク(第2回):ALGLIBのマルコフ行列を用いたバックプロパゲーション学習
量子力学の原理と最新の機械学習手法を組み合わせた、アルゴリズム取引向けの革新的な量子ニューラルネットワークアーキテクチャを紹介します。このシステムには、量子的な効果(共鳴、干渉、デコヒーレンス)、異なる時間スケールに対応した多層記憶、ALGLIBライブラリを用いたマルコフ連鎖、そして適応型パラメータ制御が組み込まれています。すべてMQL5で実装されており、組み込みの行列・ベクトル型を使用することで、MetaTrader 5でのでの実装ハードルを下げています。
科学者コミュニティ最適化 (CoSO):理論編 科学者コミュニティ最適化 (CoSO):理論編
メタヒューリスティック手法における取引戦略の効果的な最適化の秘訣。Community of Scientists Optimization (CoSO)は、科学者コミュニティの仕組みに着想を得た、集団ベースの新しい最適化アルゴリズムです。従来の自然界を模倣したメタファーとは異なり、CoSOでは、人間による科学活動の特徴的な側面、すなわち、学術誌への研究成果の発表、研究助成金をめぐる競争、研究チームの形成などをモデル化します。
科学者コミュニティ最適化 (CoSO):実装編 科学者コミュニティ最適化 (CoSO):実装編
科学コミュニティを題材にした最適化手法の話題を引き続き取り上げます。CoSOは完成されたソリューションとして捉えるべきではなく、将来性のある研究プラットフォームとして考えるべきです。適切に発展させることで、CoSOは、適応性と変化への耐性が重要であり、計算時間がそれほど重要視されないタスクにおいて、その有用性を発揮できる可能性があります。
機械学習におけるガウス過程(第1回):MQL5における分類モデル 機械学習におけるガウス過程(第1回):MQL5における分類モデル
ガウス過程の分類モデルを扱います。まず、その理論的原理について学び、続いてMQL5におけるGPライブラリの実装へと進みます。