リニアなトレーディングシステムを指数に高める
laplacianlab | 24 11月, 2015
はじめに
本稿では MQL5 プログラマーの中級者にリニアなトレーディングシステム(固定ロット)からいわゆる指数の技術を簡単に実装することでより収益を上げる方法をお伝えします。ここでは個人が負うリスクに応じてマーケットに置かれたサイズまたはポジション数を適応する資金管理モデルを参照するため累乗法の一般的な用語が使用されます。これは結果として生じる資金曲線の成長が幾何学的または指数関数で放物線の形を取ります。『リニア』という語もまた数学とプログラムの中間といったコンテキストで使用されます。特にラルフ・ビンス氏によって開発された実用的な「固定比率」のポジションサイジングの MQL5 のバリアントを実装します。
図1 数学的放物線
「資金管理モデル」を概説し、ラルフ・ビンス氏の「固定比率」ポジションサイジングのバリアントを実装する方法を確認します。準備はいいですか?みなさんのトレーディング戦略からより多くを手にする機会を見逃さないでください!
1. 資金管理モデルとは?
簡単に言えば「資金管理モデル」は概念的枠組みでその下でポジションサイズ、ストップロスの使用、マージン計算、トレードコストに関する判断をします。そこには数多くの「資金管理モデル」があります!お望みならそれら古典的な枠組みに関する知識を深めるため「固定ロット」、「固定小数」、「固定比率」、「ケリー基準」、「費用対効果」でグーグル検索することができます。申し上げたとおり、本稿では「固定比率」のバリアントしか取り上げません。
1.2. 固定比率
この資金管理モデルの背後にある考えはそれに関連する推定リスクに応じたサイジング処理です。リスクは各トレードにおいてネットで同じ比率です。
固定比率のポジションサイジングにおける契約数に対する式は以下のようなものです。
N = f ×資金 / トレードリスク
N は契約数、f は固定比率(0と1の間の数)、資金はアカウント資金の現在値、トレードリスクは契約数が計算される契約ごとのトレードのリスクです。Michael R. Bryant 著の記事Fixed Fractional Position Sizing を読んで本件に関してよりよく学習してください。
固定比率モデルの興味深いプロパティは処理サイズがアカウントのネットバランスに比例しているため、理論的には資本をすべて失うのは不可能であるということです。破滅の危険性はゼロなのです。一方、リスク資本の割合が低いため一連の処理の勝敗は利益曲線にたいした影響を与えません。
2. トレーディングシステムへの固定比率の追加
2.1. リニアなトレーディングシステムを取る
低リスク指数パワーを経験するにはまずリニアトレーディングシステムが必要です。このシステムはいわばパワー基盤の役割を果たします。リニアシステムによって特定期間に勝者と証明され、その資金曲線が直線のように見えるトレーディングシステムを意味しています。たとえば、HawaiianTsunamiSurferはコードベースで利用可能ないわゆるリニアトレーディングシステムです。その資金曲線は2012 年1月~ 2012年3月に直線に見えます。
図2 HawaiianTsunamiSurferの資金曲線(2012 年1月~ 2012年3月)
本稿の狙いはリニアトレーディングシステムを一から作成することではなくみなさんがご自身のシステムからより利益をあげるのに必要なツールを提供することです。そこで、ここからはみなさんがすでにオブジェクト指向パラダイムの下このようなトレーディングシステムを開発済みであるとしてお話します。この場合、以下で説明する OO ピースを追加する必要があります。
2.2. みなさんのシステムをパワーに高めるMQL5 のコアクラス、CEvolution
われわれのEAをコード化するためふたたびオブジェクト指向のアプローチを行います。まず記事Another MQL5 OOP class および Building an Automatic News Trader を読んでこの OO 方法で作業するための技術的基礎を入手いただくことをお薦めします。すでにこれが済んでいればこれら記事で語られている設計は CEvolutionと呼ばれるひじょうに重要なエレメントを採り入れていることを忘れないでください。これによりわれわれは既定時刻におけるロボットの状態、行われた処理履歴など重要な一時的情報を追跡することができるのです。
ここで資金管理に必要なロジックを CEvolution 内にコード化します。リスクのある固定比率は資金に比例し、そこでだれもがそれは定数ではなく変数であることに同意するので、このロジックはCEvolution内でコード化される必要があります。または簡単に言うと資金曲線の傾きは時間とともに進化するため、このすべてが実装されるべき CEvolution にあります。これはわれわれのオブジェクトプログラミングの抽象的な考え方です。それはみなさんが以下の OO クラスをご自身のオブジェクト指向スタイルのトレーディングシステムと統合する練習に残しておきます。
クラス CEvolution.mqh
//+------------------------------------------------------------------+ //| CEvolution.mqh | //| Copyright © 2013, Jordi Bassagañas | //+------------------------------------------------------------------+ #include <Mine\Enums.mqh> //+------------------------------------------------------------------+ //| CEvolution Class | //+------------------------------------------------------------------+ class CEvolution { protected: ENUM_STATUS_EA m_status; // The current EA's status ENUM_EXP_EQUITY_CURVE_LEVEL m_expEquityLevel; // The current exponential equity level double m_originalEquity; // The original equity value double m_lotSize; // The current lot size public: //--- Constructor and destructor methods CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level); ~CEvolution(void); //--- Getter methods ENUM_STATUS_EA GetStatus(void); ENUM_EXP_EQUITY_CURVE_LEVEL GetExpEquityLevel(void); double GetOriginalEquity(void); double GetLotSize(void); //--- Setter methods void SetStatus(ENUM_STATUS_EA status); void SetExpEquityLevel(ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level); void SetOriginalEquity(double equity); void SetLotSize(double size); //--- CEvolution specific methods double CalcEquityGrowth(double currentEquity); void RefreshExpEquityLevel(double currentEquity); void RefreshLotSize(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEvolution::CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_status=status; m_expEquityLevel=exp_equity_level; RefreshLotSize(); m_originalEquity=AccountInfoDouble(ACCOUNT_EQUITY); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEvolution::~CEvolution(void) { } //+------------------------------------------------------------------+ //| GetStatus | //+------------------------------------------------------------------+ ENUM_STATUS_EA CEvolution::GetStatus(void) { return m_status; } //+------------------------------------------------------------------+ //| GetExpEquityLevel | //+------------------------------------------------------------------+ ENUM_EXP_EQUITY_CURVE_LEVEL CEvolution::GetExpEquityLevel(void) { return m_expEquityLevel; } //+------------------------------------------------------------------+ //| GetEquity | //+------------------------------------------------------------------+ double CEvolution::GetOriginalEquity(void) { return m_originalEquity; } //+------------------------------------------------------------------+ //| GetLotSize | //+------------------------------------------------------------------+ double CEvolution::GetLotSize(void) { return m_lotSize; } //+------------------------------------------------------------------+ //| SetStatus | //+------------------------------------------------------------------+ void CEvolution::SetStatus(ENUM_STATUS_EA status) { m_status=status; } //+------------------------------------------------------------------+ //| SetExpEquityLevel | //+------------------------------------------------------------------+ void CEvolution::SetExpEquityLevel(ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_expEquityLevel=exp_equity_level; } //+------------------------------------------------------------------+ //| SetEquity | //+------------------------------------------------------------------+ void CEvolution::SetOriginalEquity(double equity) { m_originalEquity=equity; } //+------------------------------------------------------------------+ //| SetLotSize | //+------------------------------------------------------------------+ void CEvolution::SetLotSize(double lot_size) { m_lotSize=lot_size; } //+------------------------------------------------------------------+ //| CalcEquityGrowth | //+------------------------------------------------------------------+ double CEvolution::CalcEquityGrowth(double currentEquity) { return NormalizeDouble(currentEquity * 100 / m_originalEquity - 100,2); } //+------------------------------------------------------------------+ //| RefreshExpEquityLevel | //+------------------------------------------------------------------+ void CEvolution::RefreshExpEquityLevel(double currentEquity) { double growth = CalcEquityGrowth(currentEquity); //--- is the current equity less than 10% of the original amount? if(growth <= 10) { SetExpEquityLevel(LEVEL_ONE); } //--- is the current equity more than 10% of the original amount and less than 20%? else if(growth > 10 && growth <= 20) { SetExpEquityLevel(LEVEL_TWO); } //--- is the current equity more than 20% of the original amount and less than 30%? else if(growth > 20 && growth <= 30) { SetExpEquityLevel(LEVEL_THREE); } //--- is the current equity more than 30% of the original amount and less than 40%? else if(growth > 30 && growth <= 40) { SetExpEquityLevel(LEVEL_FOUR); } //--- is the current equity more than 40% of the original amount and less than 50%? else if(growth > 40 && growth <= 50) { SetExpEquityLevel(LEVEL_FIVE); } //--- is the current equity more than 50% of the original amount and less than 60%? else if(growth > 50 && growth <= 60) { SetExpEquityLevel(LEVEL_SEVEN); } //--- is the current equity more than 60% of the original amount and less than 70%? else if(growth > 60 && growth <= 70) { SetExpEquityLevel(LEVEL_EIGHT); } //--- is the current equity more than 70% of the original amount and less than 80%? else if(growth > 70 && growth <= 80) { SetExpEquityLevel(LEVEL_NINE); } //--- is the current equity more than 90% of the original amount? else if(growth > 90) { SetExpEquityLevel(LEVEL_TEN); } } //+------------------------------------------------------------------+ //| RefreshLotSize | //+------------------------------------------------------------------+ void CEvolution::RefreshLotSize() { switch(m_expEquityLevel) { case LEVEL_ONE: SetLotSize(0.01); break; case LEVEL_TWO: SetLotSize(0.02); break; case LEVEL_THREE: SetLotSize(0.03); break; case LEVEL_FOUR: SetLotSize(0.04); break; case LEVEL_FIVE: SetLotSize(0.05); break; case LEVEL_SIX: SetLotSize(0.06); break; case LEVEL_SEVEN: SetLotSize(0.07); break; case LEVEL_EIGHT: SetLotSize(0.08); break; case LEVEL_NINE: SetLotSize(0.09); break; case LEVEL_TEN: SetLotSize(0.1); break; } } //+------------------------------------------------------------------+
ここでこのクラスの需要箇所についてコメントします。
Expert Advisor が作成されるとき、元の資金曲線の値は m_originalEquityに格納されます。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEvolution::CEvolution(ENUM_STATUS_EA status,ENUM_EXP_EQUITY_CURVE_LEVEL exp_equity_level) { m_status=status; m_expEquityLevel=exp_equity_level; RefreshLotSize(); m_originalEquity=AccountInfoDouble(ACCOUNT_EQUITY); }
メソッド CEvolution::CalcEquityGrowth は資金曲線の成長を計算し、つねにそのもとの値に関連しています。
//+------------------------------------------------------------------+ //| CalcEquityGrowth | //+------------------------------------------------------------------+ double CEvolution::CalcEquityGrowth(double currentEquity) { return NormalizeDouble(currentEquity * 100 / m_originalEquity - 100,2); }
最後に CEvolution::RefreshExpEquityLevel はティック毎に資金レベルをリフレッシュし(それがどのように絶対的に資本成長に依存するかを観察します)CEvolution::RefreshLotSize はティック毎にロットサイズをリフレッシュします。これはみなさんの EAの OnTick メソッドで情報を以下のようにリフレッシュすることになっているためです。
GetEvolution().RefreshExpEquityLevel(AccountInfoDouble(ACCOUNT_EQUITY)); GetEvolution().RefreshLotSize();
ところでこのソリューションは次のカスタム MQL5 列挙を必要とします。
//+------------------------------------------------------------------+ //| Exponential equity curve level enumeration | //+------------------------------------------------------------------+ enum ENUM_EXP_EQUITY_CURVE_LEVEL { LEVEL_ONE, LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, LEVEL_FIVE, LEVEL_SIX, LEVEL_SEVEN, LEVEL_EIGHT, LEVEL_NINE, LEVEL_TEN };この自走は固定比率のバリアントであるとしています。それが実際いくらかの特異性を持つためです。たとえば、資金曲線はいわゆるレベル10に到達するまで指数関数的に成長し、その後システムはリニアになります。それでもなお CEvolution は資金曲線に比例してポジションサイズが絶えず増加するという基本的考えを保ちます。
2.3. 個人の固定比率判断
上述すべてでみなさんあすでにお手持ちのロボットの現状を基にして資金管理の判断を行うことができます。
みなさんの EAの OnTick メソッドのどこかで
switch(GetEvolution().GetStatus()) { case BUY: tp = ask + m_takeProfit * _Point; sl = bid - m_stopLoss * _Point; GetTrade().PositionOpen(GetBrain().GetSymbol(),ORDER_TYPE_BUY,m_evolution.GetLotSize(),ask,sl,tp); break; case SELL: sl = ask + m_takeProfit * _Point; tp = bid - m_stopLoss * _Point; GetTrade().PositionOpen(GetBrain().GetSymbol(),ORDER_TYPE_SELL,m_evolution.GetLotSize(),bid,sl,tp); break; case DO_NOTHING: // Nothing... break; }
私は新しい指数化システムの名前を ExponentialHawaiianと付けなおしました。
3. 指数化システムのバックテスト
上で説明した OO ロジックをご自身のシステムに追加したら検証の実行を忘れないでください。私はここで HawaiianTsunamiSurferの固定比率バリアントである ExponentialHawaiianをバックテストしています。
図3 ExponentialHawaiianの資金曲線(2012 年1月~ 2012年3月)
基盤となるシステムがリニアなまま、上記の曲線は指数的なままです。この条件が真でなくなると、システムは理論的破滅のリスクを伴い不安定になります。
おわりに
今日われわれは固定ロットの資金管理モデルを実装しているリニアなトレーディングシステムを累乗のパワーに引き上げることでそこからよりおおくの利益をあげる方法を学習しました。
古典的な資金管理モデルをいくつか(「固定ロット」、「固定小数」、「固定比率」、「ケリー基準」、「費用対効果」)紹介することから始め、固定比率に着目することにしました。これは処理サイズがアカウントのネットバランスに比例して維持されるシンプルなモデルです。最後にある期間のリニアな結果を示すトレーディングシステムを取り入れ、固定比率のバリアントを MQL5 に実装し、MetaTraderのストラテジーテスタによって導かれた結果を示しました。
再度われわれの Expert Advisorsにはオブジェクト指向アプローチを取り入れました。まず記事 Another MQL5 OOP class および Building an Automatic News Trader を読み、この OO 方法で作業するための技術的基礎を入手することを強くお薦めします。