ヘッジ Expert Advisor コーディングの基礎
はじめに
シンプルなヘッジ expert advisor の考え方を提供していこうと思います。ヘッジ EA の基礎の大きなメモ
ヘッジ(金融)(ウィキペディア、フリー百科事典より)
(ヘッジングからリダイレクト)
金融では、ヘッジとは別の投資でリスク を減らしたり相殺するために特別に引き出す投資を言います。ヘッジングとは、一方では、ビジネスが投資活動により利益を上げることを可能にしながら、不要なビジネスリスクへの露出を最小に抑えるために作成される戦略です。一般的にヘッジ取引を行う投資家は、『公正価格』(たとえば、それから負う住宅ローン)に相対的に低く価格設定されていると信じる証券に投資し、これを関連の証券や複数の有価証券の 空売り と組み合わせるのです。ヘッジ取引を行う投資家は、市場全体で値が上昇か下降かを気にかけません。気にかけるのは、安い値のついた証券がヘッジに対して上がるかどうかだけです。ヘッジ理論のパイオニアであるホルブルック・ワーキングはこの戦略を『基礎投機』[1]と呼びました。ここで基礎とはヘッジの理論的値と実際の値の間(またはワーキングの時代のスポットと先物の間)の差を言います。
リスクテイキングのなかにはビジネス活動に固有のものがあります。特定のビジネスにとって、リスクの一部は『当然のこと』とみなされています。価格の増減は石油掘削、精製企業にとっては当然なのです。その他のリスクは望まれませんが、ヘッジなしでは避けることができません。たとえば、店舗を所有している人は競争、低品質のまたは不人気な製品、などといったリスクに気をつけます。店主の在庫が火事にあって失われるというリスクは望まれないものですが、火災保険契約によってヘッジすることができます。ヘッジは必ずしも金融商品というわけではありません。:たとえば海外に輸出をしている製造者は、費用を希望する通貨にリンクして販売することで通貨リスクをヘッジすることもあるでしょう。
ここを参照サーバーから必要とすることはすべて MarketInfo(文字列記号、int タイプ)関数で呼び出す必要があります。この関数により現行のチャートウィンドウに表示されているデータ以上にどのようなデータでも呼び出すことができるのです。また、この関数によって、現行のチャートウィンドウに表示されているシンボル以外にもあらゆるシンボルのあらゆる種類のオーダーを送信することが可能となるのです。そしてこれで2つのシンボルを簡単にヘッジすることができます。神様と MT4 のチームメンバーのおかげで、ひじょうに助かります。
ヘッジングで一つ必要なのは、以下に示す小さないくつかの関数で見つけ出す、監視している2つのシンボルの間の「相関関係」です。
金融界での相関関係とは2つの有価証券の間の関係の統計的尺度です。相関係数の範囲は -1 と +1 の間です。+1 の相関は2つの通貨ペアが 100% 同方向に変化することを意味します。-1 の相関は2つの通貨ペアが 100% 逆方向に変化することを意味します。相関ゼロは通貨ペア間の関係が完全にランダムであることを示します。ここを参照
上記はすべて MT4 Expert Advisor を利用する Forex のヘッジャーが知る必要のあるシンプルな事柄です。ここからヘッジ EA の作成に入ります。
ヘッジ EA コード化へのステップバイステップ EA
ステップ1:入力パラメータヘッジ EA を書き始める前にまず相関シンボルを2つ選ぶ必要があります。それが以下です。
- つねに同様に変動するGBPUSD と EURUSD
- つねに逆に変動するGBPUSD と EURUSD
- * など。
本稿では、私が個人的に好むヘッジペアを選択します。それは EURJPY と GBPJPY です。それはつねに同じように変動し、ヘッジングオーダータイプの設定が簡単なものです。それでは始めましょう。ヘッジ EA の作成を始めるにあたり、以下の入力変数について学習します。
// this is to block the order sending function but // not to block the close function. extern bool BlockOpening = false; extern string BaseSymbol = "EURJPY";//the 1st symbol extern string H_Symbol = "GBPJPY";//the 2nd symbol extern bool MoveSameWay = true;//they move the same way or not extern int CorPeriod = 5;//your favorite correlation period extern double BaseLotSize = 1.5;//1st symbol lotsize extern double H_LotsSize = 1.0;//2nd symbol lotsize extern double ExpectProfit$ = 137;//your expect profit in USD //your acceptable loss in USD in case any error occurred extern double AcceptableLoss$ = -77; extern string ExpectCor = "______";//your expect correlation to hedge //this is the upper expect cor value and has to be greater than "And" extern double Between = 1.05; extern double And = 0.9;//this is the lower expect cor level extern string MISC = "______";//some thing more extern int MagicNo = 318;//your favorite magic number extern bool ShowStatus = true;//to show the present hedging status //to play sound when SendH and CloseH function done extern bool PlayAudio = false;
ステップ 2:変数宣言
以下はこの EA で使用される変数です。ここでは EA がどのように動作するか理解するのに必要な変数のみ説明していきます。
int BSP // the spread of base symbol , HSP // the spread of hedge symbol , gsp , BOP = -1 // base symbol order type , HOP = -1 // hedge symbol order type , up = 0 , Hcnt = 0 , u = 0 , d = 0 , day = 0 , sent=0 , firstopen , expire; double Lot , BaseOpen // base symbol order open price , HOpen // hedge symbol order open price , BPt // base symbol Point value , HPt // hedge symbol Point value , BSwapL // base symbol swap long value , BSwapS // base symbol swap short value , HSwapL // hedge symbol swap long value , HSwapS; // hedge symbol swap short value bool SResult = false, BResult = false, H1.profitswap, H2.profitswap, H3.profitswap; bool SwapMode = true, allmeetcor = false, BlockOpen = false, buy,sell,cleared = false; string H1.string = "", H2.string = "", H3.string = "", OrdComment = "", candletxt,tdstxt = "";
ステップ 3:必要な全静的パラメータ を取得する。
ここで init() 部分で宣言される静的な値をいくつか指定します。
//+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- BSP = MarketInfo(BaseSymbol,MODE_SPREAD); HSP = MarketInfo(H_Symbol ,MODE_SPREAD); BPt = MarketInfo(BaseSymbol,MODE_POINT); HPt = MarketInfo(H_Symbol ,MODE_POINT); BSwapL = MarketInfo(BaseSymbol,MODE_SWAPLONG); BSwapS = MarketInfo(BaseSymbol,MODE_SWAPSHORT); HSwapL = MarketInfo(H_Symbol,MODE_SWAPLONG); HSwapS = MarketInfo(H_Symbol,MODE_SWAPSHORT); //---- return(0); }
ステップ 4:有用な関数
待ち望む楽しい部分: "start()" 関数、に入る前に、本 EA で使用される関数から始めます。ただし、すべての関数は start() 関数の外にあることにご注意ください。
1. 相関関数
まず相関計算関数から始める必要があります。以下の関数は無料の相関インディケータ (igorad2004@list.ru) を提供している方からのもので、本 EA でより簡単に使用できるよう私が変更を加えました。これでもはや外部インディケータから相関値を呼ぶ必要がありません。よいアイデアでしょう?
//+------------------------------------------------------------------+ //| CORRELATION | //+------------------------------------------------------------------+ double symboldif(string symbol, int shift) { return(iClose(symbol, 1440, shift) - iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, PRICE_CLOSE, shift)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double powdif(double val) { return(MathPow(val, 2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double u(double val1,double val2) { return((val1*val2)); } //+------------------------------------------------------------------+ //| The real correlation function to call is here. | //+------------------------------------------------------------------+ double Cor(string base, string hedge) { double u1=0,l1=0,s1=0; for(int i = CorPeriod - 1; i >= 0; i--) { u1 += u(symboldif(base, i), symboldif(hedge, i)); l1 += powdif(symboldif(base, i)); s1 += powdif(symboldif(hedge, i)); } if(l1*s1 > 0) return(u1 / MathSqrt(l1*s1)); } //+------------------------------------------------------------------+
CorPeriod 変数はそれを調整できるようになるインプット変数として extern とします。2つのシンボル間の相関を計算したければ、この Cor(EURJPY,GBPJPY) のように Cor(string base,string hedge) 関数を呼ぶだけです。簡単ですよね?
2. ヘッジ送信関数
以下の SendH 関数を作成することでヘッジ注文を送信する方法が管理しやすくなると思います。
//+------------------------------------------------------------------+ //| SEND HEDGE | //+------------------------------------------------------------------+ bool SendH(string symbol, int op, double lots, double price, int sp, string comment, int magic) { if(OrderSend(symbol , op , lots , price , sp , 0 , 0 , comment , magic , 0 , CLR_NONE) > 0) { return(true); if(PlayAudio) PlaySound("expert.wav"); } else { Print(symbol, ": ", magic, " : " , ErrorDescription(GetLastError())); return(false); } } //+------------------------------------------------------------------+
OrderSend 関数に関してはここからさらに情報入手ができます。
上記の ErrorDescription(GetLastError()) 関数によりトレード関数が動作していたときどんなエラーが発生したか EA が通知するようにしてくれます。それを使用するには、以下のようなコードを入れて"stdlib.mqh" ファイルをインクルードする必要があります。
//+------------------------------------------------------------------+ //| MyHedge.mq4 | //| myHedge | //| http://dailyh.blogspot.com/ | //+------------------------------------------------------------------+ #property copyright "myHedge" #property link "http://dailyh.blogspot.com/" #include <stdlib.mqh> //+------------------------------------------------------------------+
そしてそれを使用するには、上記のように "ErrorDescription() " 関数を呼び出すだけです。
3. ヘッジ終了関数
オーダー送信以外に、期待した利益を得たらヘッジ注文を終了する関数も必要です。以下がそれです。
//+------------------------------------------------------------------+ //| CLOSE HEDGE | //+------------------------------------------------------------------+ bool CloseHedge(int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) SResult = true; } } if(SResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseHedge Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+
この関数は同一マジックナンバーの注文を終了するだけです。これは、別のマジックナンバーのヘッジ注文に影響はない、ということです。心配することではありません。この終了関数を使用する前に、以下の関数によって「今どれだけ利益を得ているか」を明確にする必要があります。
4. 総利益を求める関数
//+------------------------------------------------------------------+ //| TOTAL PROFIT | //+------------------------------------------------------------------+ double TotalCurProfit(int magic) { double MyCurrentProfit = 0; for(int cnt = 0 ; cnt < OrdersTotal() ; cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderMagicNumber() == magic) { MyCurrentProfit += (OrderProfit() + OrderSwap()); } } return(MyCurrentProfit); } //+------------------------------------------------------------------+
終了関数同様、ヘッジ利益を知るためには同一マジックナンバーの注文だけモニターし、それらを正しく終了するようにします。関数使用には以下のように呼び出します。
if(TotalCurProfit(318) > 100) CloseHedge(318);
利益の全値はUSD で計算されます。上記の行では、マジックナンバー 318 の注文の総利益が $100 より大きい場合、その注文は終了となります。以上です。ヘッジ注文を開始するには、ヘッジを送信するとき、同一シンボルおよび同一マジックナンバーの注文が宙に浮いていないことを確認する必要があります。これは以下の関数で定義することができます。
5. 既存ポジション金額を取得する
//+------------------------------------------------------------------+ //| EXISTING POSITIONS | //+------------------------------------------------------------------+ int ExistPositions(string symbol, int magic) { int NumPos = 0; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos++; } } return(NumPos); } //+------------------------------------------------------------------+
以下のように使用します。
ExistPositions("GBPJPY",318)
この関数は、そのとき現時点で「マジックナンバー 318 の GBPJPY オーダーがいくつオープンしているか」を返します。浮動オーダータイプを定義するもう一つの関数があります。
6. 特定の既存ポジションのオーダータイプを見つける
//+------------------------------------------------------------------+ //| EXISTING OP POSITION | //+------------------------------------------------------------------+ int ExistOP(string symbol, int magic) { int NumPos = -1; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos = OrderType(); } } return(NumPos); } //+------------------------------------------------------------------+
この関数は、指定されたシンボルとマジックナンバーに対して現時点で浮動のオーダータイプの整数値を返します。GBPJPY 浮動オーダーが OP_BUY であれば、返される値は "0" です。この関数はトレード関数とは連携しません。それは現在のヘッジ状態を表示する関数とも連携します。この関数は "OP2Str" と呼ばれます。
7. トレード状態を表示する
//+------------------------------------------------------------------+ //| Transform OP Value To string | //+------------------------------------------------------------------+ string OP2Str(int op) { switch(op) { case OP_BUY : return("BUY"); case OP_SELL: return("SELL"); default : return("~~"); } } //+------------------------------------------------------------------+
あまり説明することはありません。すでにどのように動作するか示していると思います。
8. 特定タイプのオーダーをすべてクローズする
ヘッジ注文を出したり終了する際エラーが発生した場合、単独のオーダーをすべて直接クローズする関数がもう一つあります。
//+------------------------------------------------------------------+ //| CLOSE SCRAP | //+------------------------------------------------------------------+ bool CloseScrap(string sym, int op, int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && amp; OrderMagicNumber() == magic && OrderSymbol() == sym && OrderType() == op) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) BResult = true; } } if(BResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseScrap Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); }
すなわち、CloseScrap("GBPJPY",OP_BUY,318) です。:これはマジックナンバー 318 の浮動の "GBPJPY" ロングだけをクローズします。簡単です。知っておくべき最後の関数です。
9. 希望のブール状態をすべて表示する
//+------------------------------------------------------------------+ //| Translate bool to string | //+------------------------------------------------------------------+ string bool2str( bool boolval) { if(boolval == true) return("Yes"); if(boolval == false) return("No"); } //+------------------------------------------------------------------+
特別なことはなにもありません。この関数は BlockOpening 値のようなパラメータのブール状態を表示します。それを真に設定する場合、この関数は画面上に「はい」を返します。偽に設定すると、「いいえ」を返します。必要な関数については以上です。ここからヘッジ処理のコーディングを楽しみましょう。
ステップ5: Expert Advisor の核
まず以下からスタートします。
//+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() {
そして相関範囲を指定します。
if(Cor(BaseSymbol, H_Symbol) > Between || Cor(BaseSymbol, H_Symbol) < And) // Block opening when the correlation is out of // expected range. BlockOpen = true; else BlockOpen = false;
次に、ヘッジ方法を定義します(これは単に一例です)。本稿では、スワップ値でトレードスタイルを選択し、それから毎日スワップから利益を得る方法でのみ取引することとします。
// if they move the same way we will open long & short if(MoveSameWay) { if(((BSwapL*BaseLotSize) + (HSwapS*H_LotSize)) > 0) { BOP = OP_BUY; HOP = OP_SELL; } else if(((BSwapS*BaseLotSize) + (HSwapL*H_LotSize)) > 0) { BOP = OP_SELL; HOP = OP_BUY; } } // end MoveSameWay // if the move the opposite way we will open short & short or long & long else { if(((BSwapL*BaseLotSize) + (HSwapL*H_LotSize)) > 0) { BOP = OP_BUY; HOP = OP_BUY; } else if(((BSwapS*BaseLotSize) + (HSwapS*H_LotSize)) > 0) { BOP = OP_SELL; HOP = OP_SELL; } }
へッジを送信するときがやってきました。
// if they meet the correlation range and // you're not blocking them if(!BlockOpen && !BlockOpening) { if(BOP == OP_BUY) // define the opening price BaseOpen = MarketInfo(BaseSymbol, MODE_ASK); else BaseOpen = MarketInfo(BaseSymbol, MODE_BID); if(HOP == OP_BUY) HOpen = MarketInfo(H_Symbol, MODE_ASK); else HOpen = MarketInfo(H_Symbol, MODE_BID); // In case there is no any swap condition to gain // from BOP & HOP will be -1. if(BOP >= 0 && HOP >= 0) { if(ExistPositions(BaseSymbol, MagicNo) == 0 && ExistPositions(H_Symbol, MagicNo) == 0) { SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, BSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); SendH(H_Symbol, HOP, H_LotsSize, HOpen, HSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); } else // in case ping failed or requote { if(ExistPositions(BaseSymbol, MagicNo) == 1&& TotalCurProfit(MagicNo)>AcceptableLoss$) { CloseScrap(BaseSymbol, ExistOP(BaseSymbol, MagicNo), MagicNo); } else if(ExistPositions(H_Symbol, MagicNo) == 1&& TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(H_Symbol, ExistOP(H_Symbol, MagicNo), MagicNo); } } } else // if one of BOP and HOP is less than 0 { string swaptxt = "No Swap Condition To Gain From :" + "pls modify one or more input parameter(s)."; } }
期待の利益が上がったら、クローズします。
if((TotalCurProfit(MagicNo) > ExpectProfit$)
{
CloseHedge(MagicNo);
}
もっと面白い事があります。 ShowStatus 部分です。
if(ShowStatus) { Comment("\nCorrel: " + DoubleToStr(Cor(BaseSymbol , H_Symbol), 2) , "\nBlockOpen : " + bool2str(BlockOpen || BlockOpening) , "\n" + swaptxt , "\n~~~~~~~" , "\nB/H [sp] : " + BaseSymbol + " [" + BSP + "]" + " / " + H_Symbol+" ["+HSP+"]" , "\nCurOp [Lots]: " + OP2Str(ExistOP(BaseSymbol, MagicNo)) + " [" + DoubleToStr(BaseLotSize, 2) + "]" + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) + " [" + DoubleToStr(H_LotsRatio*BaseLotSize, 2) + "]" , "\nCurPF [Expect]: $" + DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$"+DoubleToStr(ExpectProfit$, 2) + "]"); } else Comment("");
各 EA の終わりをもって終了します。
return(0); }
ステップ 6:すべてを集める
以下で myHedge.mq4 がどのように書かれるか確認できます。
//+------------------------------------------------------------------+ //| MyHedge.mq4 | //| myHedge | //| http://dailyh.blogspot.com/ | //+------------------------------------------------------------------+ #property copyright "myHedge" #property link "http://dailyh.blogspot.com/" //---- #include <stdlib.mqh> // this is to block the order sending function but not to block the // close function. extern bool BlockOpening = false; extern string BaseSymbol = "EURJPY"; // the 1st symbol extern string H_Symbol = "GBPJPY"; // the 2nd symbol extern bool MoveSameWay = true; // they move the same way or not extern int CorPeriod = 5; // your favorite correlation period extern double BaseLotSize = 1.5; // 1st symbol lotsize extern double H_LotSize = 1.0; // 2nd symbol lotsize extern double ExpectProfit$ = 137; // your expect profit in USD // your acceptable loss in USD in case any error occurred extern double AcceptableLoss$ = -77; extern string ExpectCor = "______"; // your expect correlation to // hedge this is the upper expect cor value and has to be greater // than "And" extern double Between = 1.05; extern double And = 0.9; // this is the lower expect cor level extern string MISC = "______"; // some thing more extern int MagicNo = 318; // your favorite magic number extern bool ShowStatus = true; // to show the present hedging status // to play sound when SendH and CloseH function done extern bool PlayAudio = false; //---- int BSP // the spread of base symbol ,HSP // the spread of hedge symbol ,gsp ,BOP = -1 // base symbol order type ,HOP = -1 // hedge symbol order type ,up = 0 ,Hcnt = 0 ,u = 0 ,d = 0 ,day = 0 ,sent = 0 ,firstopen ,expire; double Lot ,BaseOpen // base symbol order open price ,HOpen // hedge symbol order open price ,BPt // base symbol Point value ,HPt // hedge symbol Point value ,BSwapL // base symbol swap long value ,BSwapS // base symbol swap short value ,HSwapL // hedge symbol swap long value ,HSwapS; // hedge symbol swap short value bool SResult = false, BResult = false, H1.profitswap, H2.profitswap, H3.profitswap; bool SwapMode = true, allmeetcor = false, BlockOpen = false, buy, sell, cleared = false; string H1.string = "", H2.string = "", H3.string = "", OrdComment = "", candletxt,tdstxt = ""; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { BSP = MarketInfo(BaseSymbol, MODE_SPREAD); HSP = MarketInfo(H_Symbol, MODE_SPREAD); //---- BPt = MarketInfo(BaseSymbol, MODE_POINT); HPt = MarketInfo(H_Symbol, MODE_POINT); //---- BSwapL = MarketInfo(BaseSymbol, MODE_SWAPLONG); BSwapS = MarketInfo(BaseSymbol, MODE_SWAPSHORT); //---- HSwapL = MarketInfo(H_Symbol, MODE_SWAPLONG); HSwapS = MarketInfo(H_Symbol, MODE_SWAPSHORT); //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { if(Cor(BaseSymbol, H_Symbol) > Between || Cor(BaseSymbol, H_Symbol) < And) // Block opening when the correlation is out of expected range. BlockOpen = true; else BlockOpen = false; //---- if(MoveSameWay) { if((BSwapL*BaseLotSize) + (HSwapS*H_LotSize) > 0) { BOP = OP_BUY; HOP = OP_SELL; } else if((BSwapS*BaseLotSize) + (HSwapL*H_LotSize) > 0) { BOP = OP_SELL; HOP = OP_BUY; } } else { if((BSwapL*BaseLotSize) + (HSwapL*H_LotSize) > 0) { BOP = OP_BUY; HOP = OP_BUY; } else if((BSwapS*BaseLotSize) + (HSwapS*H_LotSize) > 0) { BOP = OP_SELL; HOP = OP_SELL; } } if(!BlockOpen && !BlockOpening) { if(BOP == OP_BUY) BaseOpen = MarketInfo(BaseSymbol, MODE_ASK); else BaseOpen = MarketInfo(BaseSymbol, MODE_BID); if(HOP == OP_BUY) HOpen = MarketInfo(H_Symbol, MODE_ASK); else HOpen = MarketInfo(H_Symbol, MODE_BID); // In case there is no any swap condition that we can gain from. if(BOP >= 0 && HOP >= 0) { if(ExistPositions(BaseSymbol, MagicNo) == 0 && ExistPositions(H_Symbol,MagicNo) == 0) { SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, BSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); SendH(H_Symbol, HOP, H_LotSize, HOpen, HSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); } else // in case ping failed or requote { if(ExistPositions(BaseSymbol, MagicNo) == 1 && TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(BaseSymbol, ExistOP(BaseSymbol, MagicNo), MagicNo); } else if(ExistPositions(H_Symbol, MagicNo) == 1 && TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(H_Symbol, ExistOP(H_Symbol, MagicNo), MagicNo); } } } else { string swaptxt = "No Swap Condition To Gain From : pls " + "modify one or more input parameter(s)."; } } if(TotalCurProfit(MagicNo) > ExpectProfit$) { CloseHedge(MagicNo); } if(ShowStatus) { Comment("\nCorrel: "+DoubleToStr(Cor(BaseSymbol, H_Symbol), 2) , "\nBlockOpen : " + bool2str(BlockOpen || BlockOpening) , "\n" + swaptxt , "\n~~~~~~~" , "\nB/H [sp] : " + BaseSymbol + " [" + BSP + "]" + " / " + H_Symbol + " [" + HSP + "]" , "\nCurOp [Lots]: " + OP2Str(ExistOP(BaseSymbol, MagicNo)) + " [" + DoubleToStr(BaseLotSize, 2) + "]" + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) + " [" + DoubleToStr(H_LotSize, 2) + "]" , "\nCurPF [Expect]: $" + DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$" + DoubleToStr(ExpectProfit$, 2) + "]"); } else Comment(""); return(0); } //+------------------------------------------------------------------+ //| CORRELATION | //+------------------------------------------------------------------+ double symboldif(string symbol, int shift) { return(iClose(symbol, 1440, shift) - iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, PRICE_CLOSE, shift)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double powdif(double val) { return(MathPow(val, 2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double u(double val1, double val2) { return((val1*val2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double Cor(string base, string hedge) { double u1 = 0, l1 = 0, s1 = 0; for(int i = CorPeriod - 1; i >= 0; i--) { u1 += u(symboldif(base, i), symboldif(hedge, i)); l1 += powdif(symboldif(base, i)); s1 += powdif(symboldif(hedge, i)); } if(l1*s1 > 0) return(u1 / MathSqrt(l1*s1)); } //+------------------------------------------------------------------+ //| SEND HEDGE | //+------------------------------------------------------------------+ bool SendH(string symbol, int op, double lots, double price, int sp, string comment, int magic) { if(OrderSend(symbol ,op ,lots ,price ,sp ,0 ,0 ,comment ,magic ,0 ,CLR_NONE) >0) { return(true); if(PlayAudio) PlaySound("expert.wav"); } else { Print(symbol, ": ", magic, " : " ,ErrorDescription(GetLastError())); return(false); } } //+------------------------------------------------------------------+ //| CLOSE HEDGE | //+------------------------------------------------------------------+ bool CloseHedge(int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) SResult = true; } } if(SResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseHedge Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+ //| TOTAL PROFIT | //+------------------------------------------------------------------+ double TotalCurProfit(int magic) { double MyCurrentProfit = 0; for(int cnt = 0; cnt < OrdersTotal(); cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderMagicNumber() == magic) { MyCurrentProfit += (OrderProfit() + OrderSwap()); } } return(MyCurrentProfit); } //+------------------------------------------------------------------+ //| EXISTING POSITION | //+------------------------------------------------------------------+ int ExistPositions(string symbol,int magic) { int NumPos = 0; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos++; } } return(NumPos); } //+------------------------------------------------------------------+ //| EXISTING OP POSITION | //+------------------------------------------------------------------+ int ExistOP(string symbol,int magic) { int NumPos = -1; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos = OrderType(); } } return(NumPos); } //+------------------------------------------------------------------+ //| Transform OP Value To string | //+------------------------------------------------------------------+ string OP2Str(int op) { switch(op) { case OP_BUY : return("BUY"); case OP_SELL: return("SELL"); default : return("~~"); } } //+------------------------------------------------------------------+ //| CLOSE SCRAP | //+------------------------------------------------------------------+ bool CloseScrap(string sym,int op,int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic && OrderSymbol() == sym && OrderType() == op) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) BResult = true; } } if(SResult || BResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseScrap Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+ //| Translate bool to string | //+------------------------------------------------------------------+ string bool2str(bool boolval) { if(boolval == true) return("Yes"); if(boolval == false) return("No"); } //+------------------------------------------------------------------+
おわりに
これはシンプルなヘッジ Expert Advisor の一例にすぎません。みなさんのヘッジングスタイルに合わせて変更することが必要です。みなさんには数多くのヘッジングスタイルがあるはずです。また、この種の EA はそれ自体の制限によりストラテジーテスタでは検証できないことに留意ください。本番で検証するのみです。以下はヘッジ EA の結果サンプルです。
そして以下が ShowStatus 関数です。
本稿を楽しく読んでいただけたらよいのですが。また、本稿がみなさんご自身のヘッジ EA を作成されるのに役立つことを心から願っています。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/1479
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索