EAの作成方法

EAの休止時間をcsvファイルで指定する方法

今回のテーマは、csvファイル等で指定した時間の前後は
取引をしないようにする方法です。

サンプルファイルはこちら→Sample_NoTradeTime.zip

2つのmq4ファイルと、2つのcsvファイルがありますが、
2つの対になっていて、それぞれやり方が違っています^^

どのように違うかは、
・・・^^;

また、次の機会に書きますm(_ _;)m

通常稼動で使う場合は、csvファイルをMT4→experts→filesフォルダに保存してください。
バックテストで使う場合は、MT4→tester→filesフォルダに保存してください。

でわ、このへんで^^

タグ

複数のシグナル・複数のフィルタを搭載し選択できるEA

今回のテーマは、EAの中で複数のシグナル・複数のフィルタを搭載し、
それを使うかどうかパラメータで選択できるようにする方法です。

サンプルファイルはこちら→Sample_SwitchSignal.zip
(↑'10.01.22 午前 一部修正)

Start()関数の中身は上から、

  • シグナル計算2つ
  • フィルタ計算3つ
  • エントリシグナル計算
  • エグジットシグナル計算
  • ポジション確認
  • エグジット処理
  • エントリ処理

という感じです。

シグナルが2種類、フィルタが3種類あり、
それぞれどれを使うか[Use~]というパラメータで選択できるようにしています。

シグナル計算やフィルタ計算はそれぞれ[~sign]や[~filter]といった
個別の変数に計算結果を代入します。

そして、サンプルファイル132行目~140行目を見てください。

   int sign;
   
   if((!UseMaCrossSignal || MaCrossSign==1) &&
      (!UseMacdCrossSignal || MacdSign==1) &&
      (!UseMaTrendFilter || MaFilter==1) &&
      (!UseAdxFilter || AdxFilter) &&
      (!UseAtrFilter || AtrFilter)) sign=1;
      
   if((!UseMaCrossSignal || MaCrossSign==-1) &&
      (!UseMacdCrossSignal || MacdSign==-1) &&
      (!UseMaTrendFilter || MaFilter==-1) &&
      (!UseAdxFilter || AdxFilter) &&
      (!UseAtrFilter || AtrFilter)) sign=-1;

エントリ用のシグナルを代入する整数変数 sign を宣言。
もし、
UseMaCrossSignal が false または、MaCrossSign が1で
UseMacdCrossSignal が false または、MacdSign が1で
UseMaTrendFilter が false または、MaFilter が1で
UseAdxFilter が false または、AdxFilter が true で
UseAtrFilter が false または、AtrFilter が true の場合、
signに1を代入
もし、
UseMaCrossSignal が false ・・・(省略)
・・・の場合、
signに-1を代入

といった感じにします。

これで、選択されたシグナルやフィルタのみを使ったシグナルが
sign に入ります^^

フィルタのシグナル用の変数でtrue/falseのbool型の場合は、
外でif文で書いてもいいですね^^

その下のエグジット用のシグナルの条件では
サンプルではフィルタ用の条件は含めてませんが、
書き方としては、同じ感じですね^^

そのほかで、ちょっと分かりづらいところがありますが^^;
コメントで質問してくださいね^^;

でわ、このへんで^^

タグ

VQをEA内で計算する方法

のやり方でいきますと、

extern   bool     Crash = false;
extern   int      TimeFrame = 0;
extern   int      Length = 5;
extern   int      Method = 3;
extern   int      Smoothing = 1;
extern   int      Filter = 5;
extern   int      SignShift = 1;

として、VQからコピペ&SignShiftというパラメータを追加。
そして、Start()関数内で

int sign;
sign = iCustom(NULL, TimeFrame, "VQ", Crash, 0, Length, Method, Smoothing, Filter, 6, SignShift );

とすれば、買い状態の時は、sign が1、売り状態の時は、sign が-1となり、あとは条件をいろいろと加えるだけですね^^

でも、VQ自体にいろいろな機能が付いているため、EA内で計算したほうが稼動がスムーズです。

VQを内部で計算したEAのコード

extern string  Entry_Setting  = "---------- Entry Setting";
extern double  Lots           = 0.1;
extern int     StopLoss       = 50;
extern int     TakeProfit     = 100;
extern int     Slippage       = 3;
extern int     MagicNumber    = 123456;

extern string Indicator_Setting = "---------- Indicator Setting";
extern int     TimeFrame      = 0;
extern int     Length         = 5;
extern int     Method         = 3;
extern int     Smoothing      = 1;
extern int     Filter         = 5;

extern int     EntryShift     = 1;
extern int     ExitShift      = 0;

//記憶用共通変数
int VQsign[2];    //VQのシグナル
int VQsignbar[2]; //VQのシグナルが出た場所(足の番号)
int bar;          //エントリした時の足の数(足の番号)

int init()
  {
//----
   ArrayInitialize(VQsign,0);
   ArrayInitialize(VQsignbar,0);
   bar=0;
//----
   return(0);
  }

int start()
  {
//----
   //VQ sign計算************
   FuncVQ(0);
   FuncVQ(1);
   
   //オーダーに関する部分******
   
   //現在のポジションの情報を取得
   int pos=-1;
   for(int i=OrdersTotal()-1;i>=0;i--)
   {
      OrderSelect(i,SELECT_BY_POS);
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) pos=i;
   }
   
   /*
   この時点でポジションなしの場合 pos は -1
   ポジションありの場合 pos は、そのポジションのインデックスの値
   となります。
   */
   
   //ポジション有りの場合
   if(pos>=0)
   {
      //そのポジションを選択し情報を取得できるようにする
      OrderSelect(pos,SELECT_BY_POS);
      
      if((OrderType()==OP_BUY && VQsign[ExitShift]==-1) || (OrderType()==OP_SELL && VQsign[ExitShift]==1))
         OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Yellow);
   }
   
   int ticket=0;   //注文番号を代入する変数
   double sl,tp;   //ストップとリミットを代入する変数
   
   //まだエントリしていない足で ポジションなしの場合
   if(bar!=iBars(NULL,TimeFrame) && pos<0)
   {
      //エントリ条件を計算
      int sign;
      if(VQsignbar[EntryShift]==iBars(NULL,TimeFrame)-EntryShift)
      {
         if(VQsign[EntryShift]==1) sign=1;
         if(VQsign[EntryShift]==-1) sign=-1;
      }
      
      //sign が 1 の場合
      if(sign==1)
      {
         sl=Ask-StopLoss*Point;
         if(StopLoss<=0) sl=0;
         tp=Ask+TakeProfit*Point;
         if(TakeProfit<=0) tp=0;
         ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,sl,tp,NULL,MagicNumber,0,Blue);
      }
      //sign が -1 の場合
      if(sign==-1)
      {
         sl=Bid+StopLoss*Point;
         if(StopLoss<=0) sl=0;
         tp=Bid-TakeProfit*Point;
         if(TakeProfit<=0) tp=0;
         ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,sl,tp,NULL,MagicNumber,0,Red);
      }
      //エントリした時の足の数を代入
      if(ticket>0) bar=iBars(NULL,TimeFrame);
   }
   
//----
   return(0);
  }
//+------------------------------------------------------------------+

//VQ keisan
void FuncVQ(int VQshift)
{
   double MH1,ML1,MO1,MC1,MCS1,VQ1,SumVQ1,SumVQ2;
   HideTestIndicators(true);

   if(MathAbs(VQsign[VQshift])!=1)
   {
      for(int j=0;j 0) if (MathAbs(SumVQ1 - SumVQ2) < Filter * Point) SumVQ1 = SumVQ2;

         if(SumVQ1 > SumVQ2)
         {
            if(VQsign[VQshift]==-1) break;
            
            VQsign[VQshift]=1;
            VQsignbar[VQshift]=iBars(NULL,TimeFrame)-VQshift-j;
         }
         if(SumVQ1 < SumVQ2)
         {
            if(VQsign[VQshift]==1) break;
            
            VQsign[VQshift]=-1;
            VQsignbar[VQshift]=iBars(NULL,TimeFrame)-VQshift-j;
         }
      }
   }
   
   MH1 = iMA(NULL,TimeFrame,Length,0,Method,PRICE_HIGH,VQshift);
   ML1 = iMA(NULL,TimeFrame,Length,0,Method,PRICE_LOW,VQshift);
   MO1 = iMA(NULL,TimeFrame,Length,0,Method,PRICE_OPEN,VQshift);
   MC1 = iMA(NULL,TimeFrame,Length,0,Method,PRICE_CLOSE,VQshift);
   MCS1 = iMA(NULL,TimeFrame,Length,0,Method,PRICE_CLOSE,VQshift + Smoothing);
   
   if(MathMax(MH1 - ML1,MathMax(MH1 - MCS1,MCS1 - ML1))==0 ||(MH1 - ML1)==0) return(0);
   
   VQ1 = MathAbs(((MC1 - MCS1) / MathMax(MH1 - ML1,MathMax(MH1 - MCS1,MCS1 - ML1)) + (MC1 - MO1) / (MH1 - ML1)) * 0.5) * ((MC1 - MCS1 + (MC1 - MO1)) * 0.5);
   SumVQ2 = iClose(NULL,TimeFrame,2);
   SumVQ1 = SumVQ2 + VQ1;
   if (Filter > 0) if (MathAbs(SumVQ1 - SumVQ2) < Filter * Point) SumVQ1 = SumVQ2;

   if(SumVQ1 > SumVQ2 && VQsign[VQshift]==-1)
   {
      VQsign[VQshift]=1;
      VQsignbar[VQshift]=iBars(NULL,TimeFrame)-VQshift;
   }
   if(SumVQ1 < SumVQ2 && VQsign[VQshift]==1)
   {
      VQsign[VQshift]=-1;
      VQsignbar[VQshift]=iBars(NULL,TimeFrame)-VQshift;
   }
   if(VQshift==0 && SumVQ1 == SumVQ2)
   {
      VQsign[0]=VQsign[1];
      VQsignbar[0]=VQsignbar[1];
   }
   HideTestIndicators(false);
}

今回は詳しい説明は、省略です^^;

ソースファイルもアップしますので、いろいろと改良してみてくださいね!

→VQsimple.mq4ダウンロード

でわ、今回はこのへんでm(..)m

VQの関連記事

カスタムインジケータをEAにする方法の関連記事

タグ

メール機能を追加する方法


今回は、メール機能を追加する方法の基礎の部分です^^

その前に、MT4のツール→オプション→E-メールで
有効にするにチェックし、各項目に必要事項を入力してください。


メールを送信するには、

SendMail( 題名, 本文) ;

というようにSendMail関数を書いてあげましょう。


今回は、練習として
新たな足がでたら、メールする。
メールは3回まで。
題名を【Test】
本文を【通貨ペア 足の番号】
というようにしましょうか。

でわ、早速

extern int MailCount=3;

int bar,cnt;


として、
メール発信する回数をパラメータ用整数変数 MailCount として
初期値を3としてあげましょう。
そして、記憶用整数変数 bar と cnt として、
現在の足の番号、メール送信した回数を代入するため宣言します。

次に start() 関数の{}内に


if(Bars>bar && MailCount>cnt)
{
SendMail("Test",Symbol()+" "+Bars);
bar=Bars;
cnt++;
}

としてあげましょう。

これは、

もし、足の番号がbarより大きくて、cntがMailCount未満の場合

   題名 Test
   本文 通貨ペア名 足の番号
   のメールを送信。
   barに現在の足の番号を代入。
   cntに1を足す。

といった感じの意味です。

これで、足が変わるたびにメールを送信し、MailCountで設定した回数に達したらメール送信は終わります。


こんな感じで、条件が揃ったときだけメールを送るというコードを
インディケータなどに組み込むこともできますね^^

いろいろ試してみてくださいね!

でわこのへんで^^

カスタムインディケータをEAにする方法3

下記の前回の記事と前々回の記事・・・

の続きです!

まずは、ファイルダウンロード
BBands_Stops_EA.zip(mq4ファイルのダウンロード)

  1. EAの全体構成を決める
  2. EAのパラメータを作る
  3. 条件分けをする

といった感じにやっていきましょう!

1.EAの全体構成を決める

まず、ドテンを実現するためにはシグナルでクローズするというコードが必要ですね。
ドテンするかしないかの選択ができるように、そのパラメータもつくりましょう。

ドテンする場合で、シグナルが出た瞬間の取引の場合、コストが大きくなってしまいますので、

「1度エントリしたら次の足まで待って、シグナルがダマシだった場合は
クローズして次のシグナルまで待つ」

といった取引をするようにしましょうか。

2.EAのパラメータを作る

EAを使うときに、選択できるようにするものをパラメータ化していきましょう!

エントリの時のパラメータとして

extern double Lots = 0.1;
extern int StopLoss = 0;
extern int TakeProfit = 0;
extern int Slippage = 1;

ロット数、ストップ値、リミット値、スリッページ

インディケータの使い方として

extern int SignShift = 1;
extern bool ClosebySign = true;

何本前の足のシグナルか、シグナルでクローズするか


EAのマジックナンバーもパラメータにしましょうか^^;

extern int MagicNumber = 883102;

EAでエントリしたときのコメントをパラメータにしたいときは、

string EA_Comment = "EA";

の前にexternをつけてください。


また、他のインディケータを使うときに改造しやすいように

//Other Set
string IndicatorName ="BBands_Stops_mtf";
int IndicatorUpIndex = 2;
int IndicatorDnIndex = 3;
int NoSignValue = -1;

として、インディケータ名、シグナルのインデックス、シグナルが出ていないときの値
変数に代えときましょうか。

シグナル部分は

double upsign=iCustom(NULL,TimeFrame,IndicatorName,0,Length,Deviation,
IndicatorUpIndex,SignShift);
double dnsign=iCustom(NULL,TimeFrame,IndicatorName,0,Length,Deviation,
IndicatorDnIndex,SignShift);

int sign;
if(upsign!=NoSignValue) sign=1;
if(dnsign!=NoSignValue) sign=-1;

といった形になるかと思います。

3.条件分けをする

条件分けは、

  • ポジションがあるかないか
  • シグナルがどういう状態か
  • エントリした足から足が新たにできているか

などなど・・・大まかな条件から、枝分かれするイメージで作っていきましょう。

まず、ポジションがあるか無いかを調べるために、

int pos=-1;
for(int i=OrdersTotal()-1;i>=0;i--)
{
OrderSelect(i,SELECT_BY_POS); if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber) pos=i;
}

として、
ポジションが無かったら変数posは-1
ポジションがあれば、posはそのポジションのインデックスの値

とします。

そして、

if(pos>=0)
{
}
のカッコ内にポジションがあるときに実行してもらうコード

if(pos<0)
{
}
のカッコ内にポジションが無いときに実行してもらうコード

を書いていきましょう。

まず、ポジションが無いときに実行してもらうコードを書いていきましょうか。

//MM
double lots=Lots;

として、後でマネーマネジメントの機能追加をしやすいように書いておきましょう^^

if(bar!=iBars(NULL,TimeFrame))
{

として、エントリした足(TimeFrameで指定したチャートのバー番号)では、実行しないようにします。
ここで出てくる bar は、エントリしたときのバー番号を記憶してもらう整数変数ですので、
パラメータの下あたりに、

int bar;

として、記憶用整数変数 bar を宣言しておきましょう!

そして、

if(sign==1)
{
if(TakeProfit>0) double tp=Ask+TakeProfit*Point;
else tp=0;
if(StopLoss>0) double sl=Ask-StopLoss*Point;
else sl=0;
int ticket=OrderSend(Symbol(),OP_BUY,lots,Ask,Slippage,sl,tp,EA_Comment,MagicNumber, 0,Blue); if(ticket>0) bar=iBars(NULL,TimeFrame); }

として、sign が1のときに実行してもらう内容を書いてあげましょう。

内容は、
もし、TakeProfitが0より大きい場合、小数変数tpは買値+TakeProfitピプス。
そうでない場合、tpは0。
もし、StopLossが0より大きい場合、小数変数slは買値-StopLossピプス。
そうでない場合、slは0。
指定した内容で買い注文をし、整数変数ticketに注文番号を代入。
もし、ticketが0より大きい場合、 bar にTimeFrameで指定したチャートのバー番号を代入。

という感じです。

ここで、TakeProfitやStopLossが0の場合、ストップやリミットを設定しないで注文をするといったことが出来るようになりました。
最近では、ストップやリミットが小さいとエントリを受け付けないブローカーが増えてきましたので、
MarketInfo(Symbol(),MODE_STOPLEVEL)と
MarketInfo(Symbol(),MODE_SPREAD)
ブローカーのストップ・リミット制限と
スプレッド
を使って条件わけをするとよいかと思います。
今回は省略します^^;

signが-1のときも同様に書いてあげましょう。
ここでの注意は、変数 tp,sl,ticket はすでに宣言してありますので、
変数宣言の必要がありません。

これでポジションなしの時のコードが完成しました!

次に、ポジションがあるときに実行してもらうコードを書いていきましょう!

OrderSelect(pos,SELECT_BY_POS);

として、ポジションの情報を取得できるようにポジションの選択をしておきます。

if(ClosebySign==true && bar!=iBars(NULL,TimeFrame))
{

として、ClosebySignがtrueでバー番号がエントリした足のバー番号ではないときだけ、実行してもらうようにします。

この条件は、ポジションの分岐とあわせて、

if(pos>=0 && ClosebySign==true && bar!=iBars(NULL,TimeFrame))
{
といった感じにもできますが、後から改造しやすいように分けてあります。

次に

if( (OrderType()==OP_BUY && sign==-1) || (OrderType()==OP_SELL && sign==1) )
{
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Yellow); pos=-1; }

として、買いポジションでsignが-1、または、売りポジションでsignが1のときクローズ
posに-1を代入とします。

ここで、posに-1を代入してあげると、下に書いたポジション無しの場合のコードも実行してくれるといった感じです。

そして、最後に大きな課題
「1度エントリしたら次の足まで待って、シグナルがダマシだった場合はクローズして、次のシグナルまで待つ」
を書きましょう。

if(SignShift==0 && bar==iBars(NULL,TimeFrame)-1)
{
double upsign1=iCustom(NULL,TimeFrame,IndicatorName,0,Length,Deviation,
IndicatorUpIndex,1);
double dnsign1=iCustom(NULL,TimeFrame,IndicatorName,0,Length,Deviation,
IndicatorDnIndex,1);

if( (OrderType()==OP_BUY && upsign1==NoSignValue) || (OrderType()==
OP_SELL && dnsign1==NoSignValue) )
{
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Yellow);
return(0); } }

とします。

SignShiftが0で、前の足でエントリしたときにのみ実行してもらうコードです。
また、iCustom関数で1つ前の足のシグナルをしらべます。
(signを決定するブースで記憶変数を使って調べる方法もありますが、今回はiCustom関数を使ってみましょう)

結局シグナルが出ていなかった場合、クローズする

という条件のコードを書いてあげましょう。

これで、一旦クローズしておいて、次のシグナルを待つという形になりました。

今回は、これで完成です。

あとは、ストップ・リミットが0でシグナルでもクローズしないとなるといつまででもポジションをもっていることになりますので、お好みでその条件も加えると良いかと思います。

でわ、今回はこのへんでm(..)m

カスタムインジケータをEAにする方法の関連記事

カスタムインディケータをEAにする方法

今回は、
BBands_Stops_mtf
というインディケータを使って
・途転売買を実行する/しない、の切り替え
・シグナルが出た瞬間の売買/シグナルが出た次のバーの初値で
売買の切り替え
の機能がついたEAの作り方を知りたいといったお便りを頂きましたので、
書いていこうと思います!

まずはインディケータダウンロード
BBands_Stops_mtf.zip(mq4ファイルのダウンロード)


今回のように、インディケータにマルチタイムフレーム機能(違う時間足のものを表示させる機能)がついたものは、
バックテストのビジュアルモードでちゃんと表示できなかったり、ちゃんとバックテストできなかったりしますので、気をつけなければなりません。
バックテストでもちゃんと表示させるようにするにはインディケータを修正する必要がありますので省略させていただきますね^^;


では、早速。
手順としましては、

①インディケータのインデックスを大体把握する。
②iCustom関数で必要なインデックスの値を取得する。
③シグナルに換える。

といった具合です。


①インディケータのインデックスを大体把握する。

通常のインディケータは、特別な配列(インディケータ用配列)をつかって計算します。
普通の配列とは違い、新しい足ができる度に同じように配列の先頭に1つ記憶スペースができるといった機能があります。

そのインディケータ用配列には、

SetIndexBuffer(インデックス番号,インディケータ用配列);
という形でインデックス(番号)が割り当てられています。

BBand_Stops_mtfの場合も、

init()関数の中に

SetIndexBuffer(0,UpTrendBuffer);
SetIndexBuffer(1,DownTrendBuffer);
SetIndexBuffer(2,UpTrendSignal);
SetIndexBuffer(3,DownTrendSignal);
SetIndexBuffer(4,UpTrendLine);
SetIndexBuffer(5,DownTrendLine);


といった具合に、0~5のインデックスがそれぞれ割り当てられています。

この中のどれかを使うわけですが、幸いこのインディケータの場合、

・シグナル系だということ
・インディケータ用配列の名前が分かりやすいということ

で、インディケータの表示と照らし合わせても
買いシグナルにはインデックス2番
売りシグナルにはインデックス3番
を使えばよさそうですね!


②iCustom関数で必要なインデックスの値を取得する。

では早速、Newボタンで新規EA作成しましょう!
ファイル名は、何でもよいですが、BBands_Stops_EAとしましょうか。

iCustom関数の()内の書き方は、

iCustom(通貨ペア,時間足,インディケータ名,,...,インデックス,バーシフト);

です。

インディケータ名は、文字列で入力してあげましょう。

その後ろの【,,...,】が気になりますが、ここにはインディケータのパラメータ(インディケータのプロパティで表示されるもの)が入ります。
省略することもできますが、正確には、『以下省略』という具合に、後ろ側を省略するという感じです。
なので、「1つ目のパラメータを省略して2つ目を入力する」ということができません。
インディケータのパラメータの最後のものをEAで変更して使いたいというときは、
インディケータのパラメータを全部並べてあげる必要があるわけですね^^;

インデックスはインディケータ用配列に割り振られたインデックスです。

バーシフトは、何本前の足の値を使うかという値です。
現在変動中の足での値を取得する場合は、0と入力してあげます。

以上のことを考えると、インディケータで使っているパラメータを
EAでもパラメータ化してあげる必要がありますね!

インディケータのコードの

//---- input parameters
extern int TimeFrame = 0;
extern int Length=13; // Bollinger Bands Period
extern double Deviation=1.62; // Deviation was 2

の部分をコピーして、EAのコードに貼り付けてしまいましょう!
場所は、#property ... の下あたりにしましょう。

そして、start関数の中でiCustom関数を使って、買いシグナルの値を取得してみましょう!

int start()
{
//----
double upsign=iCustom(NULL,0,"BBands_Stops_mtf",TimeFrame,Length,Deviation,2,0);

...

といった感じです。

その後、

Comment(upsign);

として、バックテストのビジュアルモードで確認してみましょう!

んが(T□T;)!!このインディケータ、バックテストではTimeFrameの機能がちゃんと作動しないようです。

こんなときは、インディケータのTimeFrameの機能をつかわず、
iCustom関数のTimeFrameの機能を使いましょう!

int start()
{
//----
double upsign=iCustom(NULL,TimeFrame,"BBands_Stops_mtf",0,Length,Deviation,2,0);

...

という具合です。

これで、TimeFrameで設定した時間足のシグナルが取得できるようになりました。
おまけに、シグナルが出ているときはシグナルの高さ(レート)の値になり、
そうでないときは、-1という値になることがわかりました(^0^)/

このComment関数を使った確認方法はいろんなケースで使えますので、
ぜひ覚えておいてくださいね!


まだ、途中ですが続きは次回とさせていただきますm(..)m

でわでわ。

VQの計算方法


今回は、VQの中身のお話です^^

VQって何?ってゆう方は
http://samuraifx.seesaa.net/article/102860052.html
↑の記事を読んでみてください^^;


VQの値は、次の計算式で割り出しています。
(説明のため形を変えてます。このままではうごきません^^;)

MH = iMA(NULL,0,Length,0,Method,PRICE_HIGH,0);
ML = iMA(NULL,0,Length,0,Method,PRICE_LOW,0);
MO = iMA(NULL,0,Length,0,Method,PRICE_OPEN,0);
MC = iMA(NULL,0,Length,0,Method,PRICE_CLOSE,0);
MCS = iMA(NULL,0,Length,0,Method,PRICE_CLOSE,Smoothing);

VQ0 = MathAbs(((MC - MCS) / MathMax(MH - ML,MathMax(MH - MCS,MCS - ML)) + (MC - MO) / (MH - ML)) * 0.5) * ((MC - MCS + (MC - MO)) * 0.5);

SumVQ= Close[1] + VQ0;
if (Filter > 0 && MathAbs(VQ0) < Filter * Point)
SumVQ = SumVQ1;

↑この【SumVQ】というのが、VQの値です。
(注意:チャートの通貨ペア・時間足、現在変動中のバーの値)


では上の方から見ていきましょうか!

MH = iMA(NULL,0,Length,0,Method,PRICE_HIGH,0);
ML = iMA(NULL,0,Length,0,Method,PRICE_LOW,0);
MO = iMA(NULL,0,Length,0,Method,PRICE_OPEN,0);
MC = iMA(NULL,0,Length,0,Method,PRICE_CLOSE,0);
MCS = iMA(NULL,0,Length,0,Method,PRICE_CLOSE,Smoothing);

VQのパラメータである、Length,Method,Smoothingはここで使われます。

それぞれ、高値、安値、始値、終値、Smoothing本前までの終値
の移動平均ですね。
ちなみに、
Lengthは平均する期間
Methodは平均の方法(4種類)
MODE_SMA 0 単純移動平均
MODE_EMA 1 指数平滑平均
MODE_SMMA 2 平滑平均
MODE_LWMA 3 加重平均
です。


VQ0 = MathAbs(((MC - MCS) / MathMax(MH - ML,MathMax(MH - MCS,MCS - ML)) + (MC - MO) / (MH - ML)) * 0.5) * ((MC - MCS + (MC - MO)) * 0.5);

さっき計算した移動平均をつかって計算します。
ここで出てくる
MathAbs はカッコ内の絶対値
MathMax は、コンマの左右でおっきい方
といった意味です。

ごちゃごちゃしてるので、紙に書いて確認してみてください^^;

MH - ML
MH - MCS
MCS - ML
の内、最大のもので
MC - MCS
を割ったものと、
MH - ML

MC - MO
を割ったものを
足して0.5をかけたものと、
MC - MCS

MC - MO
を足して0.5をかけたものを
かけた値

となるでしょうか^^;


最後に
SumVQ= Close[1] + VQ0;
if (Filter > 0 && MathAbs(VQ0) < Filter * Point)
SumVQ = SumVQ1;

VQのパラメータである、Filterはここで使われます。

一旦、SumVQ に前のバーの終値に VQ0 を足したものを代入して、
もし、Filterが0より大きくて、VQ0の絶対値がFilterピプスよりちいさかったら、
SumVQ は SumVQ1(前のバーのSumVQ)を代入。

といった感じです。

SumVQ= Close[1] + VQ0
となって、値に変化があったときにシグナルを出すのですが、
今までと同じ方向への変化はシグナルを出さないようにしてありますので、売り買い交互のシグナルになる感じです。


基本部分はこんな感じですね^^;

でわ、このへんで。

タグ

2008年11月 8日|コメント (3)トラックバック (0)

カテゴリー:EAの作成方法

記録ファイルを作ってみよう!

今回は、弱気なブルートさんのコメントにありました一定時間毎のドローダウンを記録するファイルを作るEAを作ってみましょう!

サンプルとして、ランダムエントリーでATRの数倍のトレイリングストップするシステムとして
紹介した記事「利益を出すランダムエントリーシステム!?
を使って、作ってみました。

FileWriteSample.zip(mq4ファイルをダウンロード)


内容は、ポジションが有る時、4時間足が新しくできるたびに
月、日、時間、残高、有効証拠金、現在のポジションのドローダウン、残高ピーク時からのドローダウン
を記録するという感じです。

バックテストで実行した場合は、
testerフォルダ→filesフォルダ内にファイルが作成されます。

リアルタイムで実行した場合は、
expertsフォルダ→filesフォルダ内にファイルが作成されます。


でわ、さっそくコードを見ていきましょうか(^-^)/


extern int ATRperiod=14;
extern double stoplevel=4.5;
extern double lots=0.1;
extern int Magic=216326;
extern string FileName="writesample";
extern string FileType="txt";

パラメータ用の変数です。
FileNameには、作成するファイル名を入力します。
FileTypeには、作成するファイルの拡張子を入力します。
『txt』や『log』などと入力すると、テキストファイルとなります。
『xls』と入力すると、エクセルファイルになります。

int bar;
int writebar;
double HighAB;
string filename;

記憶用の変数です。
それぞれ
整数 現在のバーの値
整数 ファイルに書き込んだ時の4時間足のバーの値
小数 過去最高の残高の値
文字列 ファイル名
です。

次に出てきますが、filenameには、パラメータで設定したファイル名と拡張子をつなげたものを記憶してもらっています。

int init()
{
//----
filename=FileName + "." + FileType;
int handle;
handle=FileOpen(filename,FILE_WRITE,"\t");
if(handle>0)
{
FileWrite(handle ,"Month","Day","Hour","Balance", "Equity", "PosDD","DD");
FileClose(handle);
}

//----
return(0);
}


int init()の{}内にスタート前にしてもらうことを書きます。

まず、
filename=FileName + "." + FileType;
で、filename にFileName と FileType をピリオドでつなげたものを代入します。
(パラメータ初期値の場合、『writesample.txt』といった具合になります。)

次に、
int handle;
handle=FileOpen(filename,FILE_WRITE,"\t");
で、handleという整数変数を宣言。
filename というファイルを書き込みモードでタブ区切り形式で開きます。
(ファイルがない場合は作成されます。)
そして、その時のファイルハンドル(ファイル認識番号みたいな感じ)を変数 handle に代入します。
FileOpen関数を使うと、指定したファイルを開くと同時に『現在開いているファイルで何番目か』という番号が割り当てられます。
ポジション確認の時のインデックス番号に似ていますね!ファイルハンドルの場合は、1から始まっているので間違えないように気をつけましょう。

そして、
if(handle>0)
{
FileWrite(handle ,"Month","Day","Hour","Balance", "Equity", "PosDD","DD");
FileClose(handle);
}
handleに正常に番号が割り当てられたら、
Month,Day,Hour,Balance,Equity,PosDD,DDという文字を書き込みます。
そして、ファイルを閉じます。
FileWrite関数のカッコ内の最初やFileClose関数のカッコ内は、ファイル名ではなく、ファイルハンドルで指定しますので気をつけましょう!

続いて、int start()のカッコ内を見ていきましょう!


//残高の最高額更新
if(AccountBalance()>HighAB) HighAB=AccountBalance();

現在の残高が HighAB に記憶しておいた値より大きい場合は、
HighAB に現在の残高を代入します。


ARTを使ったストップ用の数値の計算
ポジションの確認
ポジション無しの時

は、省略です^^;


//ポジション有りの時
else
{
(中略)
//ファイル書き込み
if(iBars(NULL,240)!=writebar)
{

ポジション有りの時で、
4時間足のバーの値が writebar に記憶しておいた値と違う場合は、
といった感じです。


次にファイルに記録したいものを変数として宣言し、値を代入していきます。

int month=TimeMonth(TimeCurrent());
int day=TimeDay(TimeCurrent());
int hour=TimeHour(TimeCurrent());

現在の月、日、時間をmonth,day,hourとし、値を代入します。


double AB=AccountBalance() ;
double AE=AccountEquity() ;

残高、有効証拠金も同様にします。


double posDD=(1-AE/AB)*100;
if(posDD<=0) string posDDstr="-";
else posDDstr=DoubleToStr(posDD,2)+"%";

小数変数 posDD を宣言し、現在の残高からのドローダウンを代入します。
そして、posDD が0以下(ドローダウンなし)の時は、文字列変数 posDDstr に『-』を代入。
それ以外(含み損が有る)時は、 posDDstr に posDD の値に『%』を付け加えたものを代入します。


double HighDD=(1-AE/HighAB)*100;
if(HighDD<=0) string HighDDstr="-";
else HighDDstr=DoubleToStr(HighDD,2)+"%";


残高ピーク時からのドローダウンも HighAB の値を使って計算し、同様にします。


int handle;
handle=FileOpen(filename,FILE_READ|FILE_WRITE,"\t");

先ほどと同じ様な感じで、読み込んダリ、書き込んダリ、...モードで^^;
タブ区切り形式で、 filename に記憶されているファイルを開きます。
この時、FILE_READモードも加えてあげないと、ファイルには上書きを繰り返して最後の書き込みしか残らなくなってしまいますので、気をつけましょう!


if(handle>0)
{

正常にファイルが開いたら、


FileSeek(handle, 0, SEEK_END);
FileWrite(handle ,month,day,hour,DoubleToStr(AB,2), DoubleToStr(AE,2), posDDstr,HighDDstr);
FileClose(handle);
writebar=iBars(NULL,240);
}
}
}//ポジション有りの時のカッコ

ファイルの最後の段にポインタを移動させ、
それぞれの値をファイルに書き込みます。
ABやAEを文字列にしているのは、テキストファイルの表示桁数をそろえるためです。文字列に変換しなくても、問題はないです^^;
そして、ファイルを閉じます。
最後に、現在の4時間足のバーの値を writebar に記憶しておいてもらいます。


こんな感じですね。


書き込みのタイミングや、記録する内容など改造したりして試してみてくださいね。


でわ、このへんで(^0^)/

PipSHakerのアルゴリズム2


今回は、前回の記事「PipSHakerのアルゴリズム1」のつづきです。


でわ、さっそく

オーダー部分です。

TrendSignが1の時

ロットの大きさを決めて、

買いロット合計がMaxTotalLots以内なら

買いオーダー送信。約定されたらtrade1をtrueに。


TrendSignが-1の時

同様に売りのオーダーです。


続いてクローズの部分です。

double WinTotal=BuyWinTotal+SellWinTotal;
double HighPoint = MathMax(HighestBuy, HighestSell);
double LowPoint = MathMin(LowestBuy, LowestSell);
double MidPoint = (HighPoint + LowPoint) / 2;

と変数の宣言をします。

WinTotal 利益が出ているポジションの利益合計
HighPoint 保持ポジションの中の最高値
LowPoint 保持ポジションの中の最安値
MidPoint HighPointとLowPointの中間値

といった感じです。


いよいよ、ここからがPipShakerのシンズイです!


①買いポジションを2つ保持、売りポジション無しで、
最安値の方の買いポジションの利益が ProfitTarget 以上のとき、
 それをクローズ。

②売りポジション無し、かつ、買いポジションが1つ以外で
 買いポジションで利益が出ているものの利益合計と、一番高く買ったポジションの損益との和が ProfitTarget 以上のとき、
一番高く買ったポジションをクローズ。
利益が出ているもの全部をクローズ。(←CloseWin()という関数を作って実行しています)

③買いポジション無し、売りポジション2つ保持で、
最高値の方の売りポジションの利益が ProfitTarget 以上のとき、
 それをクローズ。

④買いポジション無し、かつ、売りポジションが1つ以外で
 売りポジションで利益が出ているものの利益合計と、一番安く売ったポジションの損益との和が ProfitTarget 以上のとき、
一番安く売ったポジションをクローズ。
利益が出ているもの全部をクローズ。

⑤合計ポジション数が1より大きい(2以上の)とき
買値がMidPoint(保持ポジションの中間値)より上の場合で、
利益が出ているものの利益合計と、一番安く売ったポジションの損益との和が ProfitTarget 以上のとき、
 一番安く売ったポジションをクローズ。
利益が出ているもの全部をクローズ。

売値がMidPoint(保持ポジションの中間値)より下の場合で、
利益が出ているものの利益合計と、一番高く買ったポジションの損益との和が ProfitTarget 以上のとき、
 一番高く買ったポジションをクローズ。
利益が出ているもの全部をクローズ。


といった感じです。

①~④はディテールでより効率よく取引するためのもの。
⑤はPipMakerに似てますが、利益が出ているポジション全体で一番離れているポジションを相殺するようにしてあります。


次に、オブジェクト部分、ストップロス、トレイリングストップ
と続きます。
これらは、特に変わったことが無いので省略します。

トレイリングストップの部分で
if(OrdersTotal()==1 && trailingpips!=0)

if(BuyOrders + SellOrders==1 && trailingpips!=0)
に変えたほうがいいですね^^;


スタート関数を閉じた後に、

void CloseWin()

として、CloseWin()関数を作っています。

これは、利益が出ているポジション全てをクローズするといった関数になっています。


これで、おしまいですね。

サラッとだけでしたので、分からないところとかは、コメントでよろしくお願いします^^;


でわ、このへんで。

タグ

PipSHakerのアルゴリズム1


今回は、PipShakerOneのコードを使って、アルゴリズムをみていきましょう!
PipShakerV4はPipShakerOneのエントリ部分が違う感じですが、あとは大体同じです。
PipShakerOneのコードを入手できなかった人は、コードをイメージしながら読んでみてください^^;

まずは、パラメータですが、内容は過去記事の「PipShakerOne」を参照して確認してください。


double lotstep;
int lotsizing;

など記述がございますが、今回は関係ありません。
複利機能のなごり(消し忘れ)です^^;


続いて、start関数の中を見てみましょう!

double BuyLots, SellLots;
int BuyOrders = 0, SellOrders = 0;
double LowestBuy = 999, HighestBuy = 0.0001, LowestSell = 999, HighestSell = 0.0001;
double Profit, BuyProfit, SellProfit, BuyWinTotal, SellWinTotal;
int HighestBuyTicket, LowestBuyTicket, HighestSellTicket, LowestSellTicket;
double HighestBuyProfit, LowestBuyProfit, HighestSellProfit, LowestSellProfit;


変数の宣言です。

BuyLots, SellLots; 買いのロット合計,売りのロット合計
BuyOrders, SellOrders; 買いのポジション数,売りのポジション数
LowestBuy, HighestBuy; 買いポジションの中で最安値と最高値
LowestSell, HighestSell; 売りポジションの中で最安値と最高値
Profit; ポジションの損益を代入するためだけの便利変数^^;
BuyProfit, SellProfit; 買いの損益合計,売りの損益合計
BuyWinTotal, SellWinTotal; 買いの利益合計,売りの利益合計
HighestBuyTicket,LowestBuyTicket,HighestSellTicket,LowestSellTicket;
売り買いのポジションの最安値最高値のチケットナンバー
HighestBuyProfit,LowestBuyProfit,HighestSellProfit,LowestSellProfit;
売り買いのポジションの最安値最高値の損益


という感じです。

PipShakerでは、使わない変数もいくつかありますが、
改造する時とかに使えるものもあるかもですね。


つづいての73行目から128行目までのfor文は
現在保持しているポジションの情報を各変数に代入する
ための文です。

一つずつ丁寧に調べて代入!って感じです。


次に、シグナル部分に入ります。
変数の宣言int TrendSign,TradeSpace;
TrendSign シグナル
TradeSpace ←不要ですので削除してください

Trend に現在のバーの移動平均
TrendPrev に一つ前のばーの移動平均

を代入します。

シグナルの条件

if(BuyOrders + SellOrders <1 && TimeCurrent()>=Date1 && trade1==false)
{
if (buy0sell1==0) TrendSign=1;
if (buy0sell1==1) TrendSign=-1;
}

ポジションが無くて、Date1以降でtrade1がfalseの場合、
buy0sell1==0 のとき TrendSignに1を代入。
buy0sell1==1 のとき TrendSignに-1を代入。

if(BuyOrders + SellOrders >0 && TrendPrev != 0)
{

もし、ポジションがあり、TrendPrevが0ではない場合


// BUY Trade Criteria
if (TrendPrev < Trend)
{
if (Ask < LowestBuy - (Spacing * Point) || Ask > HighestBuy + (Spacing * Point))  TrendSign=1;
if(BuyOrders ==1 && SellOrders==0 && Ask > HighestBuy )  TrendSign=0;
}

移動平均が上昇の場合で、
現在の買値が買いポジションの最安値よりSpacing ピプス低いか、
現在の買値が買いポジションの最高値よりSpacing ピプス高いとき、
TrendSignに1を代入。
もし、買いポジションを1つだけ持っていて、売りポジションをもっていなくて、現在の買値が買いポジションより高いとき、
TrendSignを0にする。


// SELL Trade Criteria
if (TrendPrev > Trend)
{
if (Bid < LowestSell - (Spacing * Point) || Bid > HighestSell + (Spacing * Point))  TrendSign=-1;
if(BuyOrders ==0 && SellOrders==1 && Bid < LowestSell )
TrendSign=0;
}
}

移動平均が下降の場合、

同じ感じでTrendSignを決定します。


今日は、このへんで。
次回は、この続きでオーダーの部分からです。

タグ

サイコロジカルライン

前回maさんから、サイコロジカルラインのインディケータやEAの作り方についてのコメントを頂きましたので、早速作ってみましょうか!


ちなみにサイコロジカルラインの算出方法は

(n日間で終値比プラスの日数)÷n×100

ですね!


インディケータの作り方

まず、MetaEditorのNewボタンを押して、
Custom Indicator にチェック。

次へ

インディケータの名前を入力したら、パラメータを作るためAddボタンを押します。
今回は、インディケータの名前は「Psychological」、
パラメータは「Psycho_Period」で、タイプは int 、初期値は 12 としましょうか。

次へ

Indicator in separate window にチェック。←サブウインドウで表示
Minimum,Maximum にチェックし、Minimumを0、Maximumを100にします。

Addボタンを押して、好きな色を選びましょう!
タイプは、Lineのままでよいです。

完了


これで、コードの表面部分が出来上がりました!


後は、サイコロジカルの計算を記入するだけです。
start関数内に記入していきましょうか。

int counted_bars=IndicatorCounted();

という文が、あらかじめ書いてありますが、特に使わなくてもよさそうなので、消しちゃっても問題ないと思います^^;


int i,j, limit=Bars-IndicatorCounted();

変数の宣言です。

limitは、数えていないバーの数(最初はバーの本数、通常1、バーが増えた時2)が入っていることになります。

(実験)
Comment(Bars + "\n" + IndicatorCounted());
と加えて、1分足で見てみると Bars と IndicatorCounted() の関係が
分かり易いかもです。
(実験終わり)


for(i=limit-1; i>=0; i--)
{

まずは、計算しなければならないバーの分の繰り返し文です。

ExtMapBuffer1[i] =0;

一応、インディケータ用の配列変数の数値を初期化します。

for(j=0; j<Psycho_Period; j++)
{
if(Close[i+j]>Close[i+j+1]) ExtMapBuffer1[i]+=100;
if(Close[i+j]==Close[i+j+1]) ExtMapBuffer1[i]+=50;
}
ExtMapBuffer1[i] /=Psycho_Period;

計算するバーからPsycho_Period前までのバーの1本1本について、
終値が前のバーの終値と比べて、プラスならExtMapBuffer1[i]に100を足す。
同じなら50を足す。
Psycho_Period本分のバーを全部計算した後、Psycho_Periodで割ってあげましょう!

これで、
(n日間で終値比プラスの日数)÷n×100

の計算ができました。

}

Psychological.zip(mq4ファイルのダウンロード)


↓MT4の勉強のつよ~い味方!

FXメタトレーダー入門―最先端システムトレードソフト使いこなし術 [現代の錬金術師シリーズ56] (現代の錬金術師シリーズ 56)

EAの作り方

EAに関しては、今までどおりの作り方でやってますので、サラッといきますね^^;
(ややこしくなるといけないので、基本部分しか書いてません。各自パワーアップさせてみてください)

サイコロジカルの数値は、EAの中で計算してしまってもいいですし、
先ほど作ったインディケータ「Psychological」から、iCustom関数で取得してもよいです。

double psycho;
/* for(i=SignalTiming; i {
if(Close[i]>Close[i+1]) psyco+=100;
if(Close[i]==Close[i+1]) psyco+=50;
}
psycho /=Psycho_Period;
*/
psycho=iCustom(NULL, 0, "Psychological",Psycho_Period,0,SignalTiming);

一応このように参考のため、両方書いて片方はコメント部分にして実行しないようにしてありますので、試してみてください。


パラメータの説明

StopLoss 損切り設定ピプス
TakeProfit 利食い設定ピプス
Lots ロット数
Psycho_Period サイコロジカルの計算期間
SignalTiming シグナルを出すタイミング(現在のバーの数値でシグナル発信する場合は、0と入力。1つ前のバーで確定してからの場合は1と入力。)
BuyLevel 買い条件の数値
SellLevel 売り条件の数値
CloseBySignal 反対シグナルが出た時にクローズするかどうか

といった感じです。


Psycho_EA.zip(mq4ファイルのダウンロード)


↓プログラム作成時の辞書に最適!

【FX完全自動売買システム構築のための250の技 MetaTrader4逆引き大全集】

以上、サイコロジカルラインについてでしたが、
これ、フィルタとかに使用すると面白いかもですね!


でわ、このへんで!

マネーマネジメント

今回も、前々回同様にエクセルを使って、複利と単利の利益率とドローダウンの比較が出来るものを作りました!

compound-interest.zip(エクセルファイル「複利と単利の利益率とドローダウンの比較」)


黄色いセルにそれぞれ、

システムの勝率
1取引あたりのリスクに対する利益の比率
1取引あたりの資産に対するリスクの比率
(単利にはリスクの値そのものを入力)
初期資産

を入力します。

すると、取引1000回分の勝敗が勝率を元にランダムに決定されます。

そして、その取引1000回分の勝率と、複利単利それぞれの利率、最大ドローダウン、期待値が計算されます。

設定変更や、空いているセルにアクションを起こす度に再計算されます。

同じ設定で、何度も再計算したときに1度でも利率が-100%になってしまったら、破産リスクがあるということになります。


いろいろと、試してみてくださいね!


でわ、このへんで。


応援お願いします!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング

ポジションサイジングについて

今回は、ポジションサイジングについてのお話です!

エクセルで勝敗を自由に決められるドル円のバーチャル取引で
資金の推移がわかるものを作ってみました!

まずは、ダウンロードしてみてください。

position-sizing-test.zip(エクセルファイル「PSに対する資金の推移」)

使い方は
黄色くなっているセルを自由に設定します。

まずは、1ドルあたりいくらかを入力します。
資金と書いてある下には、初期資金、右には、取引一回あたりの資金配分率を設定します。

レバレッジと書いてある下には、配分された資金の何倍の取引をするかを入力します。
すると、その列には、何万通貨取引するのかが表示されます。

そして、リミット、ストップ、スプレッドを設定します。
この3つから、値動きがランダムウォークとした場合の勝率理論値が
計算されます。

仮(0=利,1=損)と書いてある列に、自由に勝敗を書き込んでいきます。
利食いしたときは「0」、損切りになってしまったときは「1」と入力します。

仮取引勝率の右のセルに30回の取引の勝率が表示されます。
勝率理論値と仕掛けの優位性を考慮して妥当な仮取引勝率にしてみてください。

グラフは、トレードごとの資金の推移です。

その下には、資金配分とレバレッジでテーブル機能を使い、
最終資金が算出されます。


魔術師たちの心理学 ― トレードで生計を立てる秘訣と心構え

のなかで説明されている、ポジションサイジングの話や、雪合戦の話、確率を味方につけるなどなど、
エクセルで実際に設定してみると分かり易いかもですね!

この本の中にも、ランダムエントリーに勝る仕掛けのシステムはほとんど存在しないと書いてあります。
勝率理論値と仮取引勝率の差を広げすぎると信頼性が低下していまいますので、注意してくださいね!

まだ、読んだことがない方は、
今年、新版が出たのでこちらの方がいいかもですね!

新版 魔術師たちの心理学―トレードで生計を立てる秘訣と心構え


でわ、今回はこの辺で。

応援ありがとうございます!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング

Multi_Lot_Scalperの解読4

今回はMulti_Lot_Scalperの解読の続きを見ていきましょうね!


続きはここから

Profit = 0;
LastTicket = 0;
LastType = 0;
LastClosePrice = 0;
LastLots = 0;


あれれ?
start関数の中で初めて出てきましたね。

ここで、0を代入するってことは特に記憶用ではなさそうですね^^;


つぎを見てみましょう。

//----
for(cnt = 0; cnt < OrdersTotal(); cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
//----
if(OrderSymbol() == Symbol())
{

です。
何回も出てきているお決まりのパターンなので、もうわかりますよね?

インデックス0のものから順に実行していくやつですね。


でわ次。


LastTicket = OrderTicket();
//----
if(OrderType() == OP_BUY)
LastType = OP_BUY;
//----
if(OrderType() == OP_SELL)
LastType = OP_SELL;
LastClosePrice = OrderClosePrice();
LastLots = OrderLots();


です。内容は

LastTicketに選択したポジションの注文番号を代入。
もし、ポジションが買いなら、LastType に OP_BUY を代入。
もし、ポジションがうりなら、LastType に OP_SELL を代入。
LastClosePrice に今ポジションを手仕舞いする場合の値を代入。
LastLots にポジションのロット数を代入。

です。
for文を閉じた後には、最後に代入されたものが残るわけですね。


次見てみましょうか。


//----
if(LastType == OP_BUY)
{
if(OrderClosePrice() < OrderOpenPrice())
Profit = Profit - (OrderOpenPrice() - OrderClosePrice())*OrderLots() / Point;
//----
if(OrderClosePrice() > OrderOpenPrice())
Profit = Profit + (OrderClosePrice() - OrderOpenPrice())*OrderLots() / Point;
}
//----
if(LastType==OP_SELL)
{
if(OrderClosePrice() > OrderOpenPrice())
Profit = Profit - (OrderClosePrice() - OrderOpenPrice())*OrderLots() / Point;
//----
if(OrderClosePrice() < OrderOpenPrice())
Profit = Profit + (OrderOpenPrice() - OrderClosePrice())*OrderLots() / Point;
}
 }
}

です。
内容は、

もし、LastType が OP_BUY の場合、
もし、現在の売値がエントリー値より小さいとき、
Profit に 「Profit - (エントリー値 - 現在の売値)* ロット数のピプス表示」を代入。
もし、現在の売値がエントリー値より大きいとき、
Profit に 「Profit + (現在の売値 - エントリー値)* ロット数のピプス表示」を代入。

もし、LastType が OP_SELL の場合、
もし、現在の買値がエントリー値より大きいとき、
Profit に 「Profit - (現在の買値 - エントリー値)* ロット数のピプス表示」を代入。
もし、現在の売値がエントリー値より大きいとき、
Profit に 「Profit +(エントリー値 - 現在の買値) * ロット数のピプス表示」を代入。

です。

なんだか、遠回りしてるような気がしますが^^;
Profit には、合計損益が代入されていることになります。


でわ、次です。

Profit = Profit*PipValue;
text2 = "Profit: $" + DoubleToStr(Profit,2) + " +/-";

です。内容は

Profit に Profit * PipValue を代入する。
text2 に 「Profit: $ 」と Profit の小数点以下2ケタまでを文字列にしたものと「 +/-」を
並べたものを代入する。

といった感じです。

ここで、DoubleToStrは小数を文字列に変換するときに使います。この場合は、小数点以下3桁目を
四捨五入した数字を文字列にしてあります。

パラメータのPipValueは損益をドルに換算するときに使うみたいですね。
これは、パラメータでそのつど変更するよりもプログラムのなかで計算した方が
よさそうな気がしますが^^;


でわ、次見てみましょう。

//----
if(OpenOrders >= (MaxTrades - OrderstoProtect) && AccountProtection == 1)
if(Profit >= SecureProfit)
{
OrderClose(LastTicket, LastLots, LastClosePrice, slippage, Yellow);
ContinueOpening = False;
return(0);
}


です。内容は

もし、OpenOrders がMaxTrades - OrderstoProtect 以上で AccountProtection が1の場合
もし、Profit が SecureProfit以上の時
取引番号LastTicketのものを手仕舞いにして、
ContinueOpening を False にする。
そして、終了。

といった感じです。

MaxTrades,OrderstoProtect,AccountProtection,SecureProfitの4つはパラメータ用の変数ですね。

条件が満たされて、合計利益がSecureProfit以上になったら、手仕舞いにする感じですね。
ここで一つ手仕舞いされると、前に出てきたコードで全てのポジションを手仕舞いにするという
ところにたどり着くわけですね。


でわ、次です。

//----
if(!IsTesting())
{
if(myOrderType == 3)
text="No conditions to open trades";
else
text=" ";
Comment("LastPrice=", LastPrice, " Previous open orders=", PreviousOpenOrders,
"\nContinue opening=", ContinueOpening, " OrderType=", myOrderType, "\n",
text2, "\nLots=", lotsi, "\n", text);
}

です。内容は

もし、テストではない場合、
もしmyOrderType が3ならば、textに「No conditions to open trades」を代入。
その他ならば、textに「 」を代入。
チャートに
「LastPrice=」 LastPriceの数値 「 Previous open orders=」 PreviousOpenOrdersの数値 改行
「Continue opening=」 ContinueOpeningの真偽 「OrderType=」 myOrderTypeの数値 改行
text2の文字列 改行
「Lots=」 lotsiの数値 改行
textの文字列
を表示させる。

といった感じです。

知りたい情報をチャートに表示させるときは、Commentを使いますね。


でわ、次です。


//----
if(myOrderType == 1 && ContinueOpening)
{
if((Bid - LastPrice) >= Pips*Point || OpenOrders < 1)
{
SellPrice = Bid;
LastPrice = 0;
//----
if(TakeProfit == 0)
tp = 0;
else
tp = SellPrice - TakeProfit*Point;
//----
if(InitialStop == 0)
sl = 0;
else
sl = SellPrice + InitialStop*Point;


です。内容は

もし、myOrderType が1で ContinueOpening がtrueの場合
もし、現在の売値 - LastPrice が Pipsピプス以上、または OpenOrders が1より小さい(0の)時、
SellPrice に現在の売値を代入。
LastPrice に0を代入。
もし、TakeProfit が0のとき、tp に0を代入。
その他の時は、tp に SellPrice から TakeProfitピプス引いた値を代入。
もし、InitialStop が0のとき、 sl に0を代入。
その他の時は、 sl に SellPrice と InitialStopピプスを足した値を代入。

といった感じです。

前回のエントリー値よりPipsピプス以上値上がりした時か、ポジションが無いときに
売りポジションを持つときの利食い値、損切り値を計算する感じですね。


そして、

//----
if(OpenOrders != 0)
{
mylotsi = lotsi;
//----
for(cnt = 1; cnt <= OpenOrders; cnt++)
if(MaxTrades > 12)
mylotsi = NormalizeDouble(mylotsi*1.5, 1);
else
mylotsi = NormalizeDouble(mylotsi*2, 1);
   }
   else
   mylotsi=lotsi;


です。内容は

もし、OpenOrders が0じゃない場合
mylotsi に lotsiを代入。
cntが1から OpenOrders の値の数値以下の間、次のことを実行して
cntに1を足すというのを繰り返す。
もし、MaxTrades が12より大きいときは mylotsi に mylotsi の1.5倍を小数点以下1桁にしたものを
代入。その他のときは、 mylotsi に mylotsi の1.5倍を小数点以下1桁にしたものを代入。

その他(OpenOrders が0)の場合
mylotsi に lotsi の値を代入。

という感じです。

ここは、ポジションサイジングですね。
MaxTrades が 12以下を見てみると
ポジションが1つある場合は、ロット数が2倍、
ポジションが2つある場合は、ロット数が2*2の4倍、
ポジションが3つある場合は、ロット数が4*2の8倍。
という感じです。

で、ポジションが無いときは、lotsiをそのまま代入といった感じですね。


でわ次。


  //----
if(mylotsi > 100)
mylotsi = 100;
OrderSend(Symbol(), OP_SELL, mylotsi, SellPrice, slippage, sl, tp, NULL, 0, 0,
Red);
return(0);
}
}

です。内容は

もし、mylotsi が100より大きい時はmylotsi に100を代入。
設定した内容で売り注文を出す。
で、終了。

といった感じです。

ロット数の制限を付け加えてますね。
OrderSend のカッコ内の項目も変数に代入されている値を使っています。


そして、最後


if(myOrderType == 2 && ContinueOpening)
{
if((LastPrice-Ask) >= Pips*Point || OpenOrders < 1)
{
BuyPrice = Ask;
LastPrice = 0;
//----
if(TakeProfit == 0)
tp = 0;
else
tp = BuyPrice + TakeProfit*Point;
//----
if(InitialStop==0)
sl = 0;
else
sl = BuyPrice - InitialStop*Point;
//----
if(OpenOrders != 0)
{
mylotsi = lotsi;
for(cnt = 1; cnt <= OpenOrders; cnt++)
if(MaxTrades > 12)
mylotsi = NormalizeDouble(mylotsi*1.5, 1);
else
mylotsi = NormalizeDouble(mylotsi*2, 1);
}
else
mylotsi = lotsi;
//----
if(mylotsi > 100)
mylotsi = 100;
OrderSend(Symbol(), OP_BUY, mylotsi, BuyPrice, slippage, sl, tp, NULL, 0, 0,
Blue);
return(0);
}
}
//----
return(0);
}

です。今度は買いの注文です。
内容は、売り注文の時と同じですね。

そして、start関数も終了っと。


これで全部です。なかなか分かりづらいですよね^^;

そこで、余分な情報などを削除して、取引部分を再構築してみました!

変数名やコード配置などの変更はありますが、まったく同じ取引をするものを作りました。
ブロックごとに内容をメモしてあるので参考にしてください。

しかし、このままではマネーマネジメントの部分や
損失を抱え込んでしまうなどの難ありなので、
今後改良していきたいと思います。

でわ、ダウンロード

その前に
応援よろしくお願いいたしますm(..)m
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング


MetatoreLotScalper.zip(mq4ファイル)

タグ

移動平均の交互売買の方法

今回は、xyz__さんからの質問がございましたので、
臨時記事といたしまして、

1.移動平均を上(下)に超えた直後に買い(売り)ポジションを取る。
2.買い(売り)ポジションがある場合は
ポジションを取らない。要はポジションは常に1個
3.移動平均より上(下)でポジションをとった場合は連続でポジションを同じ方向にはとらない。要は買い→売り→買い→売り・・・の法則でのみ
4.買いのポジションで決済されずに売りのポジションを持つ場合は買いを決済して売り
のポジションをもつ

というものを作りましょうか。


まずはパラメータです。

//利食い損切りピプス
extern int TakeProfit = 10;
extern int StopLoss =10;
//ロット数
extern double lots=0.1;
//移動平均の計算期間
extern int maPeriod = 21;

後から設定できる変数ですね。


次に記憶用の変数を宣言します。

int bar,LastType;

いつものように、一つのバーで1回までというようにしたいので
バーの番号を記憶する整数変数 bar と、
買い→売り→買い→売りを交互に注文することを可能にするため
最後におこなった注文を記憶する LastType という変数です。

でわ、
int start()
{
の中身を見ていきましょう!

最初に移動平均線の値を計算します。


//現在の移動平均線の値
double ma0 = iMA(NULL,0,maPeriod,0,MODE_SMA,PRICE_CLOSE,0);
//1つ前の移動平均線の値
double ma1 = iMA(NULL,0,maPeriod,0,MODE_SMA,PRICE_CLOSE,1);


ma0 , ma1 という小数変数を宣言しながら、移動平均線の値を代入しています。
このように変数が初めて出てくるところで宣言してあげても大丈夫なんですね。

今回は、【直後】というキーワードで確定前の一瞬でも超えた時点で
シグナルを出すようにしたため、現在動いている移動平均を使っています。
クロスが確定したときにシグナルを出したいときは、
iMA のカッコ内の最後の数字を1と2にして、
1つ前のバーの移動平均の値と2つ前のバーの移動平均の値を使えばいいですよね。


でわ、つぎにシグナルを出したいと思います。

//シグナル
if(Close[1]<ma1 && Close[0]>ma0) int sign=1;
if(Close[1]>ma1 && Close[0]<ma0) sign=-1;

もし、1つ前のバーの終値が移動平均値がより小さくて、かつ、
今の値が移動平均値より大きい場合は、整数変数 sign に1を代入。
もし、1つ前のバーの終値が移動平均値がより大きくて、かつ、
今の値が移動平均値より小さい場合は、整数変数 sign に-1を代入。

これで、クロスの条件が表現できますね。

1とか-1は勝手に取り決めたものですので、自由です^^;
MT4の取り決めと合わせる場合は買いが0売りが1となると思いますが、個人的に分かり易いものでいいと思います。

if文などの条件内の実行が1行の場合は{}は必要ないですね。


でわ、次です。


// オーダーチェック(ポジションなどのデータ)
int CurrentPosition=-1;
for(int cnt=0;cnt<OrdersTotal();cnt++)
{
OrderSelect(cnt,SELECT_BY_POS);
if(OrderMagicNumber() == 123 && OrderSymbol() == Symbol()) CurrentPosition=cnt;
}

この辺は、【完全自動売買への道のり】で詳しく説明してあると思うのでさらっと行きます。

整数変数 CurrentPosition の宣言で初期値は-1です。
cntが0からポジション総数の数値より小さいうちは{}内を実行しcntに1を足すというのを繰り返す。

インデックスcntのポジションを選択
もし、マジックナンバーが123でかつ、通貨ペアがチャートの通貨ペアと同じなら CurrentPosition にcntの数値を代入する。

と言った感じです。
ここで、マジックナンバーと通貨ペアを照合することによって
他のEAでおこなっている取引をカウントしない。
同じEAでおこなっている他通貨での取引をカウントしない。
という効果があります。

そして、照合した結果、マッチするもののインデックスを CurrentPosition に
代入するといった感じになります。


でわ、次行きましょう。

// ポジションチェック ポジション無し
if(CurrentPosition == -1)
{

です。
前の照合結果、CurrentPosition には何も代入されずに初期値のままのときという感じですね。
なので、【このEAでのこの通貨ペアはもっていない場合】ということになります。


//買い条件
if(bar!=Bars && LastType!=1 && sign==1)
{
//買いポジションを取る
int Ticket = OrderSend(Symbol(), OP_BUY,lots, Ask, 3, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), "test", 123, 0, Blue);
if(Ticket>0)
{
bar=Bars;
LastType=1;
}
}

もし、記憶用の変数 bar の値が今のバーの番号と違って、
記憶用の変数 LastType が1じゃなくて、
sign が1の場合は
()内の条件で買い注文を出しつつ、整数変数 Ticket に注文番号を代入する。
そして、注文番号が0より大きい(注文が成立した)とき
barに現在のバーの番号を代入。
LastTypeに1を代入。

こうしてあげれば、同じバーで複数回注文することがなく前回買い注文を出した場合、
今回は買い注文をださないといった感じになります。


//売り条件
if(bar!=Bars && LastType!=-1 && sign==-1)
{
//売りポジションを取る
Ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), "test", 123, 0, Red);
if(Ticket>0)
{
bar=Bars;
LastType=-1;
}
}

売り注文の場合も同じ様にしてあげましょう。


でわ、次に

}
// ポジション有り
else
{

です。

if(CurrentPosition == -1)のカッコを閉じてelseということは CurrentPosition が -1以外の場合、
すなわち【このEAでのこの通貨ペアはもっている場合】ということになります。


さてここからポジション有りの場合の実行コードになります。


//ポジションの選択
OrderSelect(CurrentPosition,SELECT_BY_POS);

持っているポジションの情報を知りたいときにはまずポジションの選択をしてあげなければいけません。
ここで生きてくるのが先ほどのfor文で代入されたインデックスです。
今、CurrentPositionにはfor文で照合にヒットしたインデックスが代入されているので、
そのインデックスのポジションを選択してあげるわけです。


次に、
//もし買いポジションで売りシグナルがでたら
if(OrderType()==OP_BUY && sign==-1)
{
//手仕舞い
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),3,Green);
//ドテン売り
Ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), "test", 123, 0, Red);
if(Ticket>0)
{
bar=Bars;
LastType=-1;
}
}

内容は、
もし選択されたポジションが買いで、signが-1の場合
選択されたポジションを手仕舞い。
そして、売り注文を出す。
注文成立したときbarに今のバーの番号、LastTypeに-1を代入。

といった感じです。

この取引のシグナルは一つ前のバーでsignが1になるか-1になるか
決定しているので、
同じバーで反対のシグナルが出ることがありません。
もし、同じバーで反対のシグナルが出るようなシステムでも同じバーでは複数回取引をしないという条件にする場合は、ここの条件でもbar!=Barsというものを付け加えなければなりません。


//もし売りポジションで買いシグナルがでたら
if(OrderType()==OP_SELL && sign==1)
{
//手仕舞い
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),3,Green);
//ドテン買い
Ticket = OrderSend(Symbol(), OP_BUY,lots, Ask, 3, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), "test", 123, 0, Blue);
if(Ticket>0)
{
bar=Bars;
LastType=1;
}
}

売りポジションを持っているときも同じ様にしてあげます。


そして、最後に

}

return(0);
}

elseのカッコを閉じてあげて、start関数を終了させます。


応援お願いします!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング


test10.zip(mq4ファイル)のダウンロード


でわ、今回はこの辺で。

Multi_Lot_Scalperの解読3

さあ、今回も続きを見ていきましょう!


// if we have opened positions we take care of them
for(cnt = OrdersTotal(); cnt >= 0; cnt--)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
//----
if(OrderSymbol() == Symbol())
{
if(OrderType() == OP_SELL)
if(TrailingStop > 0)
if(OrderOpenPrice() - Ask >= (TrailingStop + Pips)*Point)
if(OrderStopLoss() > (Ask + Point*TrailingStop))
{
OrderModify(OrderTicket(), OrderOpenPrice(),
Ask + Point*TrailingStop, OrderClosePrice() -
TakeProfit*Point - TrailingStop*Point, 800, Purple);
return(0);
}
if(OrderType() == OP_BUY)
if(TrailingStop > 0)
if(Bid - OrderOpenPrice() >= (TrailingStop + Pips)*Point)
if(OrderStopLoss() < (Bid - Point*TrailingStop))
{
OrderModify(OrderTicket(), OrderOpenPrice(),
Bid - Point*TrailingStop, OrderClosePrice() +
TakeProfit*Point + TrailingStop*Point, 800, Yellow);
return(0);
}
}
}

ここを一気に見てみましょうか。

内容は
//もし保持ポジションがあるならそれらを処理します。
cnt がポジション数の数値から0以上の間は、{}を実行して cnt から1を引くというのを繰り返す。

インデックスcntのポジションを選択。
もしその通貨ペアがチャートの通貨ペアと同じ場合、

もしオーダータイプが売りの時で、
もし TrailingStop が0より大きい時で、
もしエントリー値から現在の買値を引いた値より(TrailingStop + Pips)ピプスの方が小さいか等しい時で、
もし損切り値が現在の買値にTrailingStopピプス足した値の方が大きいなら、
オーダー変更
損切り値を現在の買値にTrailingStopピプス足した値に。
利食い値を現在の買値からTakeProfitピプスとTrailingStopピプスを引いた値に。
有効期限は800秒。
矢印を紫色に。
で、終了。

もしオーダータイプが買いの時で、
もし TrailingStop が0より大きい時で、
もし現在の売値からエントリー値を引いた値より(TrailingStop + Pips)ピプスの方が小さいか等しい時で、
もし損切り値が現在の売値からTrailingStopピプスを引いた値の方が小さいなら、
オーダー変更
損切り値を現在の売値からTrailingStopピプス引いた値に。
利食い値を現在の売値にTakeProfitピプスとTrailingStopピプスを足した値に。
有効期限は800秒。
矢印を黄色に。
で、終了。


という感じです。
とてもややこしいのですが、一言でゆうとトレーリングストップですね^^;

関数Pipsは、トレイリングストップを開始するのをPips分だけ遅らせるといった感じですね。

しかし、このままだと少し変わった取引になります。

初期値の損切り値0なのでそのままで考えてみましょう!

損切り値0ということはトレイリングストップ(利益確定のストップから)が発動するまでは損切りはしないことになります。


まずは、ポジションが買いの場合を考えてみましょう。

値が利益方向に(TrailingStop + Pips)ピプス上がったとき、
今の値よりTrailingStopピプス下に損切り値を持ち上げます。
と同時に、利食い値も今の値より(TakeProfit + TrailingStop)ピプス上に持ち上げます。
上がれば上がるほど利食い損切りともに上がっていきます。
そして、値が下がっているときは利食い損切りともに動かずといった感じです。
なので、買いポジションに関しては常に利確後の損切りで、
利食い値は関係ないということになりますね。
(1tickで利食い値を超えない限り)

次に、ポジションが売りの場合を考えてみましょう。

if(OrderStopLoss() > (Ask + Point*TrailingStop))という条件がありますが、
OrderStopLoss()は損切り値のことで0ですね。
なのでトレイリングストップが発動せず売りポジションには損切り値は発生しません。
なので、売りポジションに関しては利食い値まで持ち続ける感じですね。

もし、損切り値0のときもトレイリングストップを発動させる場合は、

if(OrderStopLoss() > (Ask + Point*TrailingStop) || OrderStopLoss()==0)

みたいな感じで書くと良いかと思います。

また、損切り値を設定した場合は、売り買い共に利食い値は関係なくなりますね。


モデル:Control points で利益が出ているような結果になるのは、
1tickでガツンと来るからですね^^;


まだまだ、先がありますが今日はこの辺で。

応援よろしくお願い致します!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング

タグ

Multi_Lot_Scalperの解読2

今回は、前回のMulti Lot ScalperというEAのコードの解読の続きです。

ダウンロード元はこちら↓
http://codebase.mql4.com/en/619


でわ、早速見ていきましょう!

//----
if(PreviousOpenOrders > OpenOrders)
for(cnt = OrdersTotal(); cnt >= 0; cnt--)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
mode = OrderType();
//----
if(OrderSymbol() == Symbol())
{
if(mode == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage, Blue);
//----
if(mode == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage, Red);
return(0);
}
}
PreviousOpenOrders = OpenOrders;

です。内容は

もし PreviousOpenOrders が OpenOrders より大きい場合、
cnt が所持ポジション数の数値から0以上の間は{}内を行い1を引くというのを繰り返す。

インデックスcntのポジションを選択。
mode にそのポジションのオーダータイプ(この場合成行き売りor成行き買い)を代入。
もし、そのポジションの通過ペアと現在のチャートの通貨ペアが同じ時、
もし、mode が OP_BUY ならば、手仕舞い。(矢印は青色)
もし、mode が OP_SELL ならば、手仕舞い。(矢印は赤色)
終了。

PreviousOpenOrders に OpenOrders の値を代入。


といった感じです。

最後の PreviousOpenOrders = OpenOrders; で記憶用変数 PreviousOpenOrders には
現在のポジション数が代入されていますが、
その手前までは変数名どおり記憶されている「以前のポジション数」ということになりますね。

なので、何らかの形(利食いや損切り、手仕舞いなど)でポジション数が減った時は、
PreviousOpenOrders > OpenOrders の条件に当てはまりますね。

そして、インデックスの大きい方から選択して、同じ通貨ペアがあったら手仕舞いして終了。
(実際はインデックスは0から割り当てられているので、インデックス OrdersTotal()-1 というものから実行されます)

ここで、mode を使ってオーダータイプを振り分けているのは
手仕舞いの矢印の色を区別したいからですね^^;
変数 mode の宣言を見て分かるように、 OP_BUY や OP_SELL は人には文字列のようにみえますが、
コンピュータ(MT4)は0や1といったように整数として認識しています。

ここで、一つのポジションが手仕舞いされたら return(0); によって
一旦、 int start の実行は終了です。

また、新たにint start が実行された時、同じ通貨ペアがあった場合はここでまた手仕舞いです。
これを同じ通貨ペアが無くなるまで繰り返すわけですね!

そして、同じ通貨ペアが無くなって PreviousOpenOrders = OpenOrders; までたどり着きます。
この繰り返しの後は PreviousOpenOrders , OpenOrders ともに0となるわけです。


でわ、次を見てみましょう!


//----
if(OpenOrders >= MaxTrades)
ContinueOpening = False;
else
ContinueOpening = True;


です。内容は

もし、OpenOrders が MaxTrades 以上の場合、
ContinueOpening に False を代入。
そうでない場合、
ContinueOpening に True を代入。


です。
ポジションの数を見て、追加エントリー可能かどうかを ContinueOpening に教えてあげてる感じですね。


次を見ましょうか。


//----
if(LastPrice == 0)
for(cnt = 0; cnt < OrdersTotal(); cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
mode = OrderType();
//----
if(OrderSymbol() == Symbol())
{
LastPrice = OrderOpenPrice();
//----
if(mode == OP_BUY)
myOrderType = 2;
//----
if(mode == OP_SELL)
myOrderType = 1;
}
}

です。内容は

もし LastPrice が0の場合、
cnt が0から OrdersTotal() より小さい間、{}を実行し cnt に1を足すということを繰り返す。

インデックス cnt のポジションを選択し、
mode に オーダータイプを代入。
もしその通貨ペアがチャートの通貨ペアと同じなら、
LastPrice に選択されたポジションのエントリー値を代入。
もし mode が OP_BUY なら、 myOrderType に2を代入。
もし mode が OP_SELL なら、 myOrderType に1を代入。


といった感じです。

ここでは、インデックス0のものから、 LastPrice , myOrderType に数値を代入しますが、
更に次のインデックスのものがある場合は、数値を上書きする感じですね。
そして、最後にエントリーしたポジションのデータを残す感じです。

これは、cnt を OrdersTotal()-1 からはじめて、通貨ペア確認のif文の閉じカッコの前で、
break;(←繰り返し終了の命令文)と入力しても同じですね。


次いってみましょう!


//----
if(OpenOrders < 1)
{
myOrderType = 3;
//----
if(iMACD(NULL, 0, 14, 26, 9, PRICE_CLOSE, MODE_MAIN, 0) >
iMACD(NULL, 0, 14, 26, 9, PRICE_CLOSE, MODE_MAIN, 1))
myOrderType = 2;
//----
if(iMACD(NULL, 0, 14, 26, 9, PRICE_CLOSE, MODE_MAIN, 0) <
iMACD(NULL,0,14,26,9,PRICE_CLOSE, MODE_MAIN, 1))
myOrderType = 1;
//----
if(ReverseCondition == 1)
if(myOrderType == 1)
myOrderType = 2;
else
if(myOrderType == 2)
myOrderType=1;
}

です。内容は

もし、OpenOrders が1より小さい(0の)場合、

一旦、 myOrderType に3を代入。
もし、現在のMACD(14,26)が一つ前のバーのMACD(14,26)より大きい時は、
myOrderType に2を代入。
もし、現在のMACD(14,26)が一つ前のバーのMACD(14,26)より小さい時は、
myOrderType に2を代入。
もし、ReverseCondition が1の場合で、
もしmyOrderType が1のとき、myOrderType に2を代入。
その他の場合で
もしmyOrderType が2のとき、myOrderType に1を代入。


という感じです。

先ほどは、持っているポジションのうち最後にエントリーしたもので myOrderType を決定しましたが、
今回は、ポジション無しの場合の myOrderType 決定方法ですね。

myOrderType はMACDが上向きなら2、下向きなら1、
また ReverseCondition が1の時はその逆にする、といった感じです。

またまた重要っぽい変数が出てきましたね! LastPrice , myOrderType も戦略材料っぽいですね!


ワクワクしてきたところですが、今回はこの辺で。

次回もこの続きです。


応援お願いいたします!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング


ps

メルマガ第1号は今月15日朝発行です!

タグ

Multi_Lot_Scalperの解読1

今回は、Multi Lot ScalperというEAのコードを見ていきましょうか。

ダウンロード元はこちら↓
http://codebase.mql4.com/en/619


まずは、どんなパラメータがあるかサラッと見ましょう!

extern double TakeProfit = 40;
extern double Lots = 0.1;
extern double InitialStop = 0;
extern double TrailingStop = 20;
extern int MaxTrades = 10;
extern int Pips = 15;
extern int SecureProfit = 10;
extern int AccountProtection = 1;
extern int OrderstoProtect = 3;
extern int ReverseCondition = 0;
extern double EURUSDPipValue = 10;
extern double GBPUSDPipValue = 10;
extern double USDCHFPipValue = 10;
extern double USDJPYPipValue = 9.715;
extern int StartYear = 2005;
extern int StartMonth = 1;
extern int EndYear = 2006;
extern int EndMonth = 12;
extern int EndHour = 22;
extern int EndMinute = 30;
extern int mm = 0;
extern int risk = 12;
extern int AccountisNormal = 0;

変数名で役割がなんとなく分かるものとそうでないものがありますが、
先に進めば役割が分かってきますので、サラッとみます^^;

記憶用の変数もサラッ!と見ましょう。

//----
int OpenOrders = 0, cnt = 0;
int slippage = 5;
double sl = 0, tp = 0;
double BuyPrice = 0, SellPrice = 0;
double lotsi = 0, mylotsi = 0;
int mode = 0, myOrderType = 0;
bool ContinueOpening = True;
double LastPrice = 0;
int PreviousOpenOrders = 0;
double Profit = 0;
int LastTicket = 0, LastType = 0;
double LastClosePrice = 0, LastLots = 0;
double Pivot = 0;
double PipValue = 0;
string text = "", text2 = "";


今のところは、「こんな変数をここで宣言しているんだな~」程度で
良いかと思います。


でわ早速 int start() の中身を見ていきましょう!


if(AccountisNormal == 1)
if(mm != 0)
lotsi = MathCeil(AccountBalance()*risk/10000);
else
lotsi=Lots;
else
// then is mini
if(mm != 0)
lotsi = MathCeil(AccountBalance()*risk / 10000) / 10;
else
lotsi = Lots;
//----
if(lotsi > 100)
lotsi = 100;

個人的にはif文が重なるときは{}があったほうが見やすいのですが^^;

内容は

もし AccountisNormal が1の時で
mm が0ではない場合
lotsi に口座残高* risk /10000 の小数点以下切り上げを代入。
その他(mm が0)の場合
lotsiにLotsを代入。

//ミニの場合
その他の( AccountisNormal が1ではない)時で
mm が0ではない場合
lotsi に口座残高* risk /10000/10 の小数点以下切り上げを代入。
その他(mm が0)の場合
lotsiにLotsを代入。

もしlotsi が100より大きい時
lotsiに100を代入。


という感じです。

ここで MathCeil() はカッコ内の数値を小数点以下繰り上げといった感じです。
繰り上げなので、数値がマイナスの時、たとえば-2.999の時は-2に繰り上がります。

あと、変数 mm はマネーマネジメントのイニシャルという感じですね。

mmをオン(0以外)にした場合、lotsi をロット数にするには大きい感じがしますね。


でわ、次を見てみましょう。


OpenOrders = 0;
//----
for(cnt = 0; cnt < OrdersTotal(); cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
//----
if(OrderSymbol() == Symbol())
OpenOrders++;
}


です。内容は

念のため OpenOrders を0にしておいて、

cnt が0から オーダー(この場合は所持ポジション)の総数より小さい内は
{}内を行い cnt に1を足すということを繰り返します。

インデックス cnt のポジションを選択し
もしその通貨ペアが現在のチャートの通貨ペアと同じ場合
OpenOrders に1を足す。


といった感じです。

所持ポジションのうち現在のチャートの通貨ペアの数を OpenOrders で表す感じですね。


続いて


//----
if(OpenOrders < 1)
{
if(TimeYear(CurTime()) < StartYear)
return(0);
//----
if(TimeMonth(CurTime()) < StartMonth)
return(0);
//----
if(TimeYear(CurTime()) > EndYear)
return(0);
//----
if(TimeMonth(CurTime()) > EndMonth )
return(0);
}


ですが、内容は

もし OpenOrders が1より小さい(0の)場合で、

もし、現在の年が StartYear より小さい時、終了。
もし、現在の月が StartMonth より小さい時、終了。
もし、現在の年が EndYear より大きい時、終了。
もし、現在の月が EndMonth より大きい時、終了。


といった感じです。

これは、ちょっと気になりますね・・・。
このままだと、たとえば
StartYear = 2005
StartMonth = 10
EndYear = 2007
EndMonth = 8

とした場合、現在の月が10月より小さい場合は、終了。
現在の月が8月より大きい場合は、終了。
ということは、いつでもここで終了ということになってしまいます。

何年何月~何年何月までというような条件を作る時は

if(TimeYear(CurTime()) < StartYear)
return(0);
//----
if(TimeMonth(CurTime()) < StartMonth && TimeYear(CurTime()) == StartYear)
return(0);
//----
if(TimeYear(CurTime()) > EndYear)
return(0);
//----
if(TimeMonth(CurTime()) > EndMonth && TimeYear(CurTime()) == EndYear)
return(0);

とするとできますね。
今回の条件はまた別の意味があるかもしれませんので
先に進みましょうか^^;


続いては、


//----
if(Symbol() == "EURUSD")
PipValue = EURUSDPipValue;
//----
if(Symbol() == "GBPUSD")
PipValue = GBPUSDPipValue;
//----
if(Symbol() == "USDJPY")
PipValue = USDJPYPipValue;
//----
if(Symbol() == "USDCHF")
PipValue = USDCHFPipValue;
//----
if(PipValue == 0)
{
PipValue = 5;
}


です。

内容は、

もし現在のチャートの通貨ペアがEURUSDの時、PipValue に EURUSDPipValue を代入。
(後の3つも同じ感じ)
もし PipValue が0の時、PipValue に5を代入。


といった感じです。
PipValue が0の時というのは、PipValue に何も代入されていなくて
初期値のままか、0が代入された時というわけですね。
もし PipValue が正の数じゃないとマズい時はif(PipValue <= 0) とした方がいいかもですね。

それにしても、PipValue は何に使うんでしょうね。ワクワクしますね!


このワクワクは、次回まで持ち越しましょうか。

でわ、今回はこの辺で。


応援ありがとうございます!
→FXシステムトレード派
→rank応援クリック
→人気ブログランキング


ps
メルマガ登録ありがとうございます。
まだ、第1号を発行してないのですが、登録数にビックリしています^^;
第1号は来週あたりを予定しております。お楽しみに!

タグ

zyx40さんのルール検証2

前回の記事(zyx40さんのルール検証)で、zyx40さんの使用したEAと紹介しましたが、ご指摘があり訂正しました。正しくは、zyx40さんのEAのベースのようです。申し訳ございません。
このEAにzyx40さんの考えをプラスしたそうです。


さあ!

前回の続きを見ていきましょう!

int start(){}の中身ですね。

if((TimeHour(TimeCurrent())>TradeTime)) cantrade=true;

となってます。

ここで、TimeHour(TimeCurrent())は現在の時間ということです。
例えば、現在 19:25 だとすると、TimeHour(TimeCurrent())は19という数字になります。
もっと、分解してみていきましょうか。

TimeHour() のカッコ内に、1970年1月1日0時0分0秒から何秒経った時の事かを入れてあげるとその時の時間を計算してくれます。
TimeCurrent() は、現在、1970年1月1日0時0分0秒から TimeCurrent() 秒経ってますよっと言った感じで秒数を計算してくれます。
それで、TimeHour(TimeCurrent())は現在の時間ということになります。

TradeTime はパラメータ用の変数、 cantrade は記憶用の変数でしたね。
なので、「もし現在の時間が TradeTime より大きかったら cantrade を true にしてください」といった意味になります。


次に、

// проверяем есть ли открытые ордера ...
total=OrdersTotal();

としています。
//オープンオーダーがあるかどうかをチェック
というメモと、
OrdersTotal()で調べたポジションの数を total という変数に代入してくださいという文ですね。

次、

if(total<Orders)
{

もし、total がパラメータで指定した Orders より小さい場合はという意味ですね。


// ... если нет ни одного открытого ордера, то идем дальше
// проверяем настало ли время для торговли
if((TimeHour(TimeCurrent())==TradeTime)&&(cantrade))
{
// ... если настало время, то

//もし取引権利がない場合、飛ばします
//時間をチェックします

もし、現在の時間がTradeTime でかつcantradeがtrueの場合。

//もしその時間の場合

といった感じです。


次に
if (((Open[t1]-Open[t2])>delta_S*Point)) //Если цена уменьшилась на величину delta
{

もしt1の始値からt2の始値を引いたものがdelta_S*Pointより大きい場合といった意味ですね。
//もし価格がデルタ量より減少してたら

という具合です。ここの部分がこのEAの心臓部分のような感じですね!


次に

//условие выполнено значит входим в короткую позицию:
// проверяем есть ли свободные деньги для открытия короткой позиции
if(AccountFreeMarginCheck(Symbol(),OP_SELL,lot)<=0 || GetLastError()==134)
{
Print("Not enough money");
return(0);
}

となってます。

//条件が満たされたら売り注文を出す
//売り注文を出す余剰証拠金があるかどうかをチェック

ここで、AccountFreeMarginCheck() という関数を使っています。
これは、仮にカッコ内の指定(通貨、売りor買い、ロット数)通りオーダーした場合、余剰証拠金はいくらになるかを教えてくれる関数です。もし、指定したオーダーが出来ないときはエラー番号134というエラーを出します。(エラー134は資金不足というエラーです)

なので、
もしこの通貨をlotロット売った時の余剰証拠金が0以下、または最後に生じたエラーが134ならば
Not enough money と表示させて
実行終了してください

という意味になります。


そして

OpenShort(lot);

cantrade=false; //запрещаем торговать повторно до следующего бара
return(0);
}

ここで出てきましたね!自作の関数OpenShort。

カッコ内のlot(初期設定では0.1)という数字を引き連れて、
OpenShortという関数を宣言したところに一旦移ります。宣言した所のカッコ内はvolumeとなっていますので、この場合は、volumeにlotを代入。そして一通りOpenShort関数の内容を実行したらまた戻ってきます。

OpenShort関数の中で、売り注文を出してますね。

その後、「cantradeをfalseにしてください」としています。
メモは、//次のバー(時間)まで再売り禁止
という感じです。

そして、実行終了ですね。


次に

if (((Open[t2]-Open[t1])>delta_L*Point))

として、今度はdelta_L*Pointより大きく値が上がった場合の時の処理です。買い注文のプログラムですね。

内容は、売りの時と同じ感じです。説明は省略^^;

そして、if((TimeHour(TimeCurrent())==TradeTime)&&(cantrade))とif(total<Orders)のカッコを閉じてます。


次に
// блок проверки времени жизни сделки, если MaxOpenTime=0, то проверку не проводим.

として、
//保持ポジションの残り時間をチェックする部分です。もし、MaxOpenTimeが0なら、この確認プロセスはおこないません。

という感じです。

では、見ていきましょう。

if(MaxOpenTime>0)
{

MaxOpenTime が0より大きい場合、ですね。
なので、MaxOpenTime が0以下ならこの確認プロセスは実行されないことになります。

次に、

for(cnt=0;cnt<total;cnt++)
{

として、繰り返しのfor文が使ってありますね。
cntが0からtotalより小さいうちはcntに1を足しつつ繰り返してくださいといった感じです。
なので、例えばtotalが3の場合は、cntが0、1、2の3回繰り返されるということです。

そして、
if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
{

として、そのcntが使われてます。

「もしインデックスcntのポジションを選択したときtrueになったら」
といった意味ですね。

次にここで
tmp = (TimeCurrent()-OrderOpenTime())/3600.0;

としてtmpに現在と選択されたポジションのオープン時の秒差を3600で割ったものを代入しています。
これは、選択されたポジションを何時間保持してるかを計算しtmpに入れているわけですね。

次に
if (((NormalizeDouble(tmp,8)-MaxOpenTime)>=0))
{

としています。経過時間 - MaxOpenTimeが0以上の場合という意味です。
ここで、NormalizeDouble(小数値,0~8)という関数は、小数値の第何位(0~8)の後ろで四捨五入するといった関数です。
例えば、
NormalizeDouble(3.1415,3)
とすれば、
3.142
というように小数点以下第3位の後ろで四捨五入した値になります。

この場合、私が調べたところNormalizeDoubleを使っても使わなくても値は変わりませんでした。


次に
RefreshRates();

としてます。
これは、EAの計算時間が長くて Ask や Bid といったあらかじめ作ってある変数の値をもう一度取得する必要があるときに使います。
文字通りレートのリフレッシュですね。

そして、

if (OrderType()==OP_BUY)
closeprice=Bid;
else
closeprice=Ask;

として選択されたポジションが買いの場合、closeprice に現在の売値を代入。その他(ポジションが売り)の場合、closeprice に現在の買値を代入。
といった感じです。


次に
if (OrderClose(OrderTicket(),OrderLots(),closeprice,10,Green))

として、そのポジションを手仕舞いしてます。
と同時にOrderCloseはbool型の関数というのを利用して
「この手仕舞いが無事に取引された(OrderClose関数がTrueになった)場合」
というif文にしています。

{
Print("Принудительное закрытие сделки - №",OrderTicket());
OrderPrint();
}
else
Print("OrderClose() в блоке проверки времени жизни сделки вернул ошибку - ",GetLastError());


として、
「強制手仕舞い-No」という文字と選択されたポジションのチケットナンバーをつなげたものを表示してください。
選択されたポジションの情報を表示してください。

そうでない場合(OrderClose関数がfalseの場合)は

「 保持ポジションの残り時間をチェックする部分のOrderClose()でエラーが返されました - 」という文字とエラーナンバーをつなげたものを表示してください。

といった感じです。

ここでOrderPrint()は、
チケットナンバー、エントリーの時間、売りor買い、ロット数、通貨、エントリーの値、損切り値、利食い値、手仕舞いの値、手数料、スワップ、売買差益、コメント、マジックナンバー
といった感じで表示されます。


そして、
if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))の終わりカッコのあとの

else
Print("OrderSelect() в блоке проверки времени жизни сделки вернул ошибку - ",GetLastError());
}

として、ポジション選択できなかった場合の処理を書いてます。

保持ポジションの残り時間をチェックする部分のOrderSelect()でエラーが返されました - エラーナンバー
を表示してください。といった意味です。

次の閉じカッコはfor文の閉じカッコです。ここまできたらcntに1を足してまたfor文以下を繰り返します。


最後に

}
return(0);
}

として、保持ポジションの残り時間をチェックする部分の始のif文のカッコを閉じて、実行終了、int start終了。

です。


エントリー時間を決めて、その時の過去数時間の始値の差で売りor買いを決める。ポジションには寿命がある。
といった売買ルールですね。

今回はこのへんで。


次回は、zyx40さんはどのようにしたのか。パラメータをどう変えたらいいのかなどを書きたいと思います。


応援ありがとうございます!
→FXシステムトレード派
→rank応援クリック

タグ

2007年12月28日|コメント (4)トラックバック (0)

カテゴリー:EAの作成方法

EA作成の為のテンプレート

今日は、まだ一度もExpert Advisorを作ったことがない人のために
テンプレートなるものを作りました!
移動平均と終値を使った単純ルールです。エントリーのフィルタも移動平均を使った単純なものです。利益は望めません^^;

移動平均の代わりに何かをつかったり、フィルタを変えたり、シグナルの条件を変えたりしてみましょう!

プログラミングの練習に役立てていただけたらうれしいです。
→template.zip


本当に応援ありがとうございます!
→FXシステムトレード派
→rank応援クリック


ps
素敵なクリスマスをお過ごしください(^0^)/

2007年12月24日|コメント (7)トラックバック (0)

カテゴリー:EAの作成方法

Optimization機能の少し変わった活用法

今回は、Optimization 機能の少し変わった使い方を紹介!


週1回、決まった時間に買いポジションを持ち、決まった時間に決済する
といった売買ルールを作り、曜日や時間をパラメータ化することで、
過去の一定期間において、レートが上がり易かった時間がわかるというもの。


今回は、先月の下げの中での上がりやすかった時間を調べてみましょう!

まずは、
パラメータですね!

extern int TakeProfit=100;
extern int StopLoss=50;
extern int OpenWeek,OpenHour,OpenMinute,CloseHour,CloseMinute;

としましょうか。TakeProfit や StopLoss は無くてもいいのですが
指定した結果も調べられるように付け加えてあります。

その下の変数は、ポジションを取る曜日、時間、分、手仕舞いの時間、分です。
ここで、手仕舞いの曜日が無いのは、24時間以内に手仕舞いするため
指定してません。
(1週間以内に手仕舞いするというルールでは CloseWeek が必要になります。)

そして、記憶用の変数として

int bar;

と書きます。


次に

int start()
{

return(0);
}

の中身を書いていきましょう!

指標の計算が無いのでいきなりオーダーです^^;
まず、

int OpenPos = OrdersTotal();

として変数 OpenPos にポジションの数を代入します。

次に、

if (OpenPos < 1)//ポジション無し
{

}

として、{}内にポジション無しの時のオーダー条件とオーダーを書いていきましょう!


if(bar!=Bars
&& TimeDayOfWeek(CurTime()) == OpenWeek
&& TimeHour(CurTime()) == OpenHour
&& TimeMinute(CurTime()) >= OpenMinute)
{
OrderSend(Symbol(), OP_BUY, 1, Ask, 3, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), "Buy", 0, 0, Blue);
bar=Bars;
}

です。
上から、
bar が Bars ではない
今の曜日が OpenWeek のとき
今の時間が OpenHour のとき
今の分が OpenMinute 以上のとき
です。

ここで、TimeDayOfWeek(CurTime()) は今の曜日を数字の0~6で表すものです。
0の日曜日から6の土曜日までです。

そして、OrderSend でオーダーし記憶用の変数 bar に Bars を代入。

ここで、 OpenMinute 以上のときとしたのは、たまたま OpenMinute で指定した
分のデータが無かったとき(変動がなかった等)、次の分でオーダーするためです。

また、1時間足以上を使わないと次のバーでもオーダーしてしまうということが起こるので注意してください!


次に、

if(OpenPos >0)//ポジション有り
{

}

として、{}内にポジション有りの時の手仕舞い条件と手仕舞いを書いていきましょう!


if(TimeHour(CurTime()) == CloseHour && TimeMinute(CurTime()) >= CloseMinute)
{
//ポジションのデータを取得
OrderSelect(0,SELECT_BY_POS);
OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);
}

こちらも、同じような感じですね!手仕舞いの時間と分で手仕舞いの
注文を出します。

コードは以上です。

CalculationProgram(TimeTrade_Buy).zip(mq4ファイル)

コピペします↓

//+------------------------------------------------------------------+
//| CalculationProgram(TimeTrade_Buy).mq4 |
//| SAMURAI |
//| http://samuraifx.seesaa.net/ |
//+------------------------------------------------------------------+
#property copyright "SAMURAI"
#property link "http://samuraifx.seesaa.net/"

extern int TakeProfit=100;
extern int StopLoss=50;
extern int OpenWeek,OpenHour,OpenMinute,CloseHour,CloseMinute;
int bar;

int start()
{

//Order
int OpenPos = OrdersTotal();
if (OpenPos < 1)//ポジション無し
{

if(bar!=Bars && TimeDayOfWeek(CurTime()) == OpenWeek && TimeHour(CurTime()) == OpenHour && TimeMinute(CurTime()) >= OpenMinute)
{
OrderSend(Symbol(), OP_BUY, 1, Ask, 3, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), "Buy", 0, 0, Blue);
bar=Bars;
}
}
if(OpenPos >0)//ポジション有り
{
if(TimeHour(CurTime()) == CloseHour && TimeMinute(CurTime()) >= CloseMinute)
{
//ポジションのデータを取得
OrderSelect(0,SELECT_BY_POS);
OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);
}
}
return(0);
}


さて、これをコンパイルしたらいよいよです!
メタトレーダーのテスターでCalculationProgram(TimeTrade_Buy),SUMURAI を選び、
通貨は USDJPY にしときますか。
モデルで Every tick を選ぶとすごく時間がかかるので
今回は、Control points にしましょうか。
(時間に余裕があるときは Every tick で調べてみましょう)

日付と時間を使用にチェックをいれて2007年11月の月初めから月末までを選びます。

そして、ここから重要です!
Expert properties をクリック。
Testingタブを選択。Initial deposit を10000のUSDにしときましょう。
パラメーターの入力タブを選択。
TakeProfit と StopLoss は100と50のままにしときましょうか。
OpenWeek 以下5コにチェックを入れます。スタートの列は全て0のままにしておきましょう。
OpenWeek のステップは1。ストップは6。
OpenHour のステップは1。ストップは23。
OpenMinute のステップは10にしましょうか。となるとストップは50。10分おきに調べるということですね。
CloseHour と CloseMinute も同じように1と23、10と50といった具合です。
OpenWeek に0や6も含めるのは、業者によってデータの時間が違っていて、週の最初のデータが日曜日の夜から始まってたりするので、全てで調べてみましょう。(蓄積データはツールのHistory Center でみれます。)

そして、OKボタンを押して、Optimization にチェックを入れましょう!
期間は、H1 以上にしなければなりません。今回はH1でやってみましょう。

いよいよ計算開始です!スタートボタンを押してしばらく待ちましょう!


その間に、一旦CMです。

金持ち父さん貧乏父さん

↑世界中のみんなが読んだ本。日本でも200万人以上が読んでます。
金持ち父さんシリーズの1作目。このシリーズを読んでない人は、まず入門編としておすすめします!
私はこの本で、お金(収入)に対する概念がガラリと変わりました!


はいっ。
計算が終了しましたら、Optimization Results タブをクリックして、
結果を見てみましょう!利益が出た曜日と時間の組み合わせが表示されています。
OpenよりもCloseの方が早い時間の場合は次の日の手仕舞いということになります。

でも、このままではチョットわかりづらいので、私はエクセルにコピーして見たりします。
やり方は、データのどこでもいいので右クリックして、Copy All を選択。エクセルを開いて2段目に貼り付け。一段目に項目を入力して、一段目全てを選択。データ→フィルタ→オートフィルタです。
これで、いろんな条件で絞り込んで見たりできます。
Profit factor が空欄(または0)のデータは勝率100%ということになります。

こんな具合にして、利食い損切り幅を狭めたらどうかとか、過去1年間の傾向や売りの場合はどうなのか、CloseWeek を加えて、一週間以内で手仕舞いするシステムではどうなのか(計算時間がかなり長くなってしまいますが^^;)、などいろいろ試すことができます。

今回は、このへんで。


次回は、FX システムトレード派ブログランキング現在6位の【MetaTraderでFX自動売買ブログ】さんの12月13日の記事が気になっていますので、そちらの研究と検証をして、記事を書きたいと思います!

みなさんのおかげでランキング順位があがってきています!
ありがとうございますm(._.)m
にほんブログ村 為替ブログ FX システムトレード派へポプログ人気fxブログランキング

2007年12月16日|コメント (2)トラックバック (0)

カテゴリー:EAの作成方法

ポジションサイジング

今回は、ポジションサイジングについてです。

ポジションの大きさを決めるとき、よく使われるのが複利システムにする方法でも紹介した、
口座残高に応じて取引額を決定するといった方法ですが、

今回はそれに『システムの調子』の要素も加えてみましょうか。

『システムの調子』の定義は、
単純に今何連勝中か?または、何連敗中か?といった感じにしました。

ルールの設定
・基本レバレッジは10倍。
・2連勝したら11倍、3連勝したら12倍というようにレバレッジを
 一つずつ増やしていき、最大20倍まで。
・2連敗したら10倍の2分の1、すなわち5倍。3連敗なら3分の1、
 すなわち約3.33倍。というように減らしていきます。


では実際に構築していきましょう!

今回も前の記事(トレイリングストップ)のランダムエントリーのシステムに
付け加える感じでやってきます。

まずはじめに、
記憶させておきたいものは、今何連勝中かまたは、何連敗中かといった
情報ですね。
これを変数の記憶させる箇所に

int win,loss;

と宣言しましょう。

さらに、勝ち負けを判断するために手仕舞い前の残高を記憶させます。

double LastBalance;

とします。

次に初期設定として int init() の{}内に

LastBalance=AccountBalance();

としておきます。


次にいよいよ連勝連敗の計算ですよ!

//Entry
OpenPos = OrdersTotal();
if (OpenPos < 1)//ポジション無し
{
の下あたりに


//win,lossの算出
if(AccountBalance()>LastBalance)
{
win=win+1;
loss=0;
}
if(AccountBalance()<LastBalance)
{
loss=loss+1;
win=0;
}
LastBalance=AccountBalance();

としましょう。

これは、ポジションが無くて、前の残高より今の残高の方が大きい時は
変数 win に1を足して、変数 loss を0にしましょう。
 逆に、前の残高より今の残高の方が小さい時は
変数 loss に1を足して、変数 win を0にしましょう。
そして、変数 LastBalance に今の残高を記憶させましょう。

といった意味ですね!


続いてその下に


//lotsの算出
double leverage=10;
if( win != 0 ) leverage = 9+win;
if( loss != 0 ) leverage = 10/loss;
if( leverage >20) leverage = 20;
int ilots = AccountBalance() * leverage / 10000;
double lots = ilots * 0.1 ;
if(lots<=0.1) lots=0.1;
if(lots>=1000) lots=1000;

としましょう。

これは、ポジションサイズの最終決定です!
leverage という変数の宣言は上の方で StopLoss や TakeProfit を宣言した
のと併せてもいいですよね。今回はlotsの算出のまとまりのところで
宣言させてもらいました。初期値は10ですね。
(最初の取引は win も loss も 0 なので、初期値が適用されます。)

和訳^^;というと、

もし win が 0 じゃなかった(前回の取引は勝ちだった)ら、
leverage に 9+win を代入しましょう。

(ここで、 9+win としたのは、1回勝ちで leverage は 10 に、
 2連勝で leverage が 11 にするためです。)

もし loss が 0 じゃなかった(前回の取引は負けだった)ら、
leverage に 10/loss を代入しましょう。

ここでもし leverage が 20 より大きかったら、
leverage を 20 としましょう。

整数 ilots に残高に leverage をかけて、一万で割った数を
代入します。

小数 lots に ilots*0.1 を代入しましょう。

もし lots が最小最大を超えた場合は最小値、最大値にする。

といった感じです。
後半の計算は前の複利システムの記事と同じ感じですね!


後は、 OrderSend の()内のロット数を入力する場所に lots と
書き換えるだけです。


ここで一旦、CMです。


FX完全自動売買システム構築のための250の技 MetaTrader4逆引き大全集

↑プロのプログラマーが全編書き下ろし。
まさにプログラムを勉強したい人にはうってつけの書籍!


FXメタトレーダー入門―最先端システムトレードソフト使いこなし術

↑神奈川大学工学部教授が書いた本。今月発売されました!


はい!
では、
いつものようにできあがったコードをコピペしたいと思います!


//+------------------------------------------------------------------+
//| Matsui.mq4 |
//| SAMURAI |
//| http://samuraifx.seesaa.net/ |
//+------------------------------------------------------------------+
#property copyright "SAMURAI"
#property link "http://samuraifx.seesaa.net/"

//パラメータ用の変数
extern int StopLossPer =3;
extern int TakeProfitPer = 5;
extern int TrailingStopPer =50;
extern int TrailingStopStartPer =1;
extern int Frequency = 10;

extern int BandsPeriod=4;
extern double TrailingStopStartBandsPerBid =1.5;

//記憶用の変数
double StopLoss,TakeProfit,TrailingStopStart;
int Bar,MaxVolume;

int win,loss;
double LastBalance;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
MathSrand(LocalTime());
LastBalance=AccountBalance();
//----
return(0);
}

//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
//変数の宣言
double StopLoss, TakeProfit, TrailingStop, Width, AWidth;
int Pos, Type, OpenPos;

//Entry抽選
Pos = MathRand() % (Frequency + 1);
Type = MathRand() % (1 + 1);

//Entry
OpenPos = OrdersTotal();
if (OpenPos < 1)//ポジション無し
{
//win,lossの算出
if(AccountBalance()>LastBalance)
{
win=win+1;
loss=0;
}
if(AccountBalance()<LastBalance)
{
loss=loss+1;
win=0;
}
LastBalance=AccountBalance();

//lotsの算出
double leverage=10;
if( win != 0 ) leverage = 9+win;
if( loss != 0 ) leverage = 10/loss;
if( leverage >20) leverage = 20;
int ilots = AccountBalance() * leverage / 10000;
double lots = ilots * 0.1 ;
if(lots<=0.1) lots=0.1;
if(lots>=1000) lots=1000;

//MaxVolumeのリセット
MaxVolume = 0;
//Buy
if (Pos == 0 && Type == 0 && Bars != Bar)
{
//Order時の値決定と記録
StopLoss = Close[0] * StopLossPer / 100;
TakeProfit = Close[0] * TakeProfitPer /100;
TrailingStopStart = Close[0] * TrailingStopStartPer /100;
Bar = Bars;
//Order
OrderSend(Symbol(), OP_BUY, lots, Ask, 3, Ask-StopLoss, Ask+TakeProfit, "Buy", 616, 0, Blue);
return(0);
}
//Sell
if (Pos == 0 && Type == 1 && Bars != Bar)
{
//Order時の値決定と記録
StopLoss = Close[0] * StopLossPer / 100;
TakeProfit = Close[0] * TakeProfitPer /100;
TrailingStopStart = Close[0] * TrailingStopStartPer /100;
Bar = Bars;
//Order
OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Bid+StopLoss, Bid-TakeProfit, "Sell", 616, 0, Red);
return(0);
}
}


if(OpenPos >0)//ポジション有り
{
//bandの幅
double BandsWidth = iBands(NULL,0,BandsPeriod,1,0,PRICE_CLOSE,MODE_UPPER,0)
- iBands(NULL,0,BandsPeriod,1,0,PRICE_CLOSE,MODE_LOWER,0);
double BandsPerBid = BandsWidth / Bid * 100;

//Volumeの確認
if(Volume[1] > MaxVolume) MaxVolume = Volume[1];
//10日間の平均振幅の算出
for(int i=3;i<13;i++)
{
Width = Width + High[i] - Low[i];
}
AWidth = Width / 10;
//ポジションのデータを取得
OrderSelect(0,SELECT_BY_POS);
//買いポジション
if(OrderType()==OP_BUY)
{
//Trailing stop
TrailingStop=OrderOpenPrice()+(Bid-OrderOpenPrice())*TrailingStopPer/100;
if(Bid>OrderOpenPrice()+TrailingStopStart && OrderStopLoss()<TrailingStop && BandsPerBid>TrailingStopStartBandsPerBid)
{
OrderModify(OrderTicket(),OrderOpenPrice(),TrailingStop,OrderTakeProfit(),0,Magenta);
return(0);
}
//急騰による手仕舞い
if(Bid > OrderOpenPrice() + TakeProfit * 0.3 &&
Close[2] - Open[2] > AWidth * 3 &&
Volume[2] > MaxVolume * 0.9 &&
Volume[2] > Volume[1] * 2)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Red);
}
}
if(OrderType()==OP_SELL)
{
//Trailing stop
TrailingStop=OrderOpenPrice()-((OrderOpenPrice()-Ask)*TrailingStopPer/100);
if(Ask<OrderOpenPrice()-TrailingStopStart && OrderStopLoss()>TrailingStop && BandsPerBid>TrailingStopStartBandsPerBid)
{
OrderModify(OrderTicket(),OrderOpenPrice(),TrailingStop,OrderTakeProfit(),0,Magenta);
return(0);
}
//急落による手仕舞い
if(Ask < OrderOpenPrice() - TakeProfit * 0.3 &&
Open[2] - Close[2] > AWidth * 3 &&
Volume[2] > MaxVolume * 0.9 &&
Volume[2] > Volume[1] * 2)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Blue);
}
}

}
//----
return(0);
}
//+------------------------------------------------------------------+

次回は、
今のところ安定して利益を出している優良ルール VolAve に、
このポジションサイジングの方法を適用した結果と
それに対するあれこれです^^;

お楽しみに!にほんブログ村 為替ブログ FX システムトレード派へ

2007年12月11日|コメント (6)トラックバック (0)

カテゴリー:EAの作成方法

トレイリングストップ2

前々回の記事トレイリングストップの続きです。

今回は、トレイリングストップを機能させる条件を付け加えたいと思います。

その条件とは、いままでの条件に
ボリンジャーバンドの幅が一定以上になったら、
トレイリングストップを機能させる

といったものをさらに加えたいと思います。


まずは、パラメータとして

extern int BandsPeriod=4;
extern double TrailingStopStartBandsPerBid =1.5;

とします。
これは、ボリンジャーバンドに使う平均移動線の計算期間と
『ボリンジャーバンドの幅が一定以上になったら』というところの
値です。
後にでてきますが今回は『バンド(標準偏差1倍)の上下幅が売値の1.5%になったら』
ということにしました。

次に、計算として

if(OpenPos >0)//ポジション有り
{

の後に

//bandの幅
double BandsWidth = iBands(NULL,0,BandsPeriod,1,0,PRICE_CLOSE,MODE_UPPER,0)
- iBands(NULL,0,BandsPeriod,1,0,PRICE_CLOSE,MODE_LOWER,0);
double BandsPerBid = BandsWidth / Bid * 100;


としてます。
これは、iBands関数を使って、バンドの上下幅を計算し、
変数 BandsWidth に代入。
つぎに、BandsWidth が売値の何パーセントかを計算し、
変数 BandsPerBid に代入。
といった感じです。

最後に、

if(Bid>OrderOpenPrice()+TrailingStopStart && OrderStopLoss()<TrailingStop && BandsPerBid>TrailingStopStartBandsPerBid)


のようにトレイリングストップを機能させる条件文の部分に
&& BandsPerBid>TrailingStopStartBandsPerBid

と付け加えます。

これで、値動きが大きいときだけトレイリングストップを機能させる
といったものになりました!


次回は、ポジションサイジングについてです。にほんブログ村 為替ブログ FX システムトレード派へ

2007年12月 8日|コメント (2)トラックバック (0)

カテゴリー:EAの作成方法

トレイリングストップ

今日は、手仕舞いの仕方について書いていこうと思います。

All Aboutのマネーの記事の松井宗則氏の手法を参考にします!

・ロスカットは2~3%
・利益確定はロスカット幅以上
・最大含み益の50%まで下落したら一旦利益確定
・30%以上含み益が出て、過去最大級の出来高で急騰後、
 出来高が半減したら一旦利益確定

以上の条件で、仕掛けのタイミングはランダムエントリーにしました。
(ランダムエントリー参考記事→SKILL UP FX!さんの記事


この数値では、中期トレード向きかと思います。デイトレや短期トレードに対応できるように、パラメータ化しました。

ロジック内容は、
・パラメータ
ロスカットパーセンテージ
利益確定パーセンテージ
トレーリングストップパーセンテージ
トレーリングストップ開始パーセンテージ
ランダムエントリー確率

・エントリー抽選

・エントリー
ロスカット値の算出
利益確定値の算出
トレーリングストップ開始値の算出

・ポジション保持時
平均振幅の算出
トレイリングストップ
急騰急落時の手仕舞い

といった具合です。


30%以上含み益が出て、過去最大級の出来高で急騰後、
出来高が半減したら一旦利益確定という部分を
どのようにしようか悩みましたが、
今回は、

・30%以上含み益
エントリーから利益確定値までを100%とし、その30%で算出。

・過去最大級の出来高
エントリーからの最大出来高を記憶させ、その90%以上。

・急騰
過去10日間の平均振幅の3倍上昇。

・出来高が半減
急騰時の出来高の50%未満。

(急落時も同様に)

といった感じで定義しました^^;


検証結果はというと、通貨によってまちまちですが、
パラメータやその他の値を変更するなどして、
手仕舞いの方法の一つとして、覚えておいても良いのではと思います。

コードをコピペしますので、ご指摘やご質問などなどありましたら、
ぜひお聞かせくださいm(._.)m


//+------------------------------------------------------------------+
//| Matsui.mq4 |
//| SAMURAI |
//| http://samuraifx.seesaa.net/ |
//+------------------------------------------------------------------+
#property copyright "SAMURAI"
#property link "http://samuraifx.seesaa.net/"

//パラメータ用の変数
extern int StopLossPer =3;
extern int TakeProfitPer = 5;
extern int TrailingStopPer =50;
extern int TrailingStopStartPer =1;
extern int Frequency = 100;

double StopLoss,TakeProfit,TrailingStopStart;
int Bar,MaxVolume;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
MathSrand(LocalTime());
//----
return(0);
}

//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
//変数の宣言
double StopLoss, TakeProfit, TrailingStop, Width, AWidth;
int Pos, Type, OpenPos;

//Entry抽選
Pos = MathRand() % (Frequency + 1);
Type = MathRand() % (1 + 1);

//Entry
OpenPos = OrdersTotal();
if (OpenPos < 1)//ポジション無し
{
//MaxVolumeのリセット
MaxVolume = 0;
//Buy
if (Pos == 0 && Type == 0 && Bars != Bar)
{
//Order時の値決定と記録
StopLoss = Close[0] * StopLossPer / 100;
TakeProfit = Close[0] * TakeProfitPer /100;
TrailingStopStart = Close[0] * TrailingStopStartPer /100;
Bar = Bars;
//Order
OrderSend(Symbol(), OP_BUY, 1, Ask, 3, Ask-StopLoss, Ask+TakeProfit, "Buy", 616, 0, Blue);
return(0);
}
//Sell
if (Pos == 0 && Type == 1 && Bars != Bar)
{
//Order時の値決定と記録
StopLoss = Close[0] * StopLossPer / 100;
TakeProfit = Close[0] * TakeProfitPer /100;
TrailingStopStart = Close[0] * TrailingStopStartPer /100;
Bar = Bars;
//Order
OrderSend(Symbol(), OP_SELL, 1, Bid, 3, Bid+StopLoss, Bid-TakeProfit, "Sell", 616, 0, Red);
return(0);
}
}


if(OpenPos >0)//ポジション有り
{
//Volumeの確認
if(Volume[1] > MaxVolume) MaxVolume = Volume[1];
//10日間の平均振幅の算出
for(int i=3;i<13;i++)
{
Width = Width + High[i] - Low[i];
}
AWidth = Width / 10;
//ポジションのデータを取得
OrderSelect(0,SELECT_BY_POS);
//買いポジション
if(OrderType()==OP_BUY)
{
//Trailing stop
TrailingStop=OrderOpenPrice()+(Bid-OrderOpenPrice())*TrailingStopPer/100;
if(Bid>OrderOpenPrice()+TrailingStopStart && OrderStopLoss()<TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),TrailingStop,OrderTakeProfit(),0,Magenta);
return(0);
}
//急騰による手仕舞い
if(Bid > OrderOpenPrice() + TakeProfit * 0.3 &&
Close[2] - Open[2] > AWidth * 3 &&
Volume[2] > MaxVolume * 0.9 &&
Volume[2] > Volume[1] * 2)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Red);
}
}
if(OrderType()==OP_SELL)
{
//Trailing stop
TrailingStop=OrderOpenPrice()-((OrderOpenPrice()-Ask)*TrailingStopPer/100);
if(Ask<OrderOpenPrice()-TrailingStopStart && OrderStopLoss()>TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),TrailingStop,OrderTakeProfit(),0,Magenta);
return(0);
}
//急落による手仕舞い
if(Ask < OrderOpenPrice() - TakeProfit * 0.3 &&
Open[2] - Close[2] > AWidth * 3 &&
Volume[2] > MaxVolume * 0.9 &&
Volume[2] > Volume[1] * 2)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Blue);
}
}

}
//----
return(0);
}

2007年12月 1日|コメント (0)トラックバック (0)

カテゴリー:EAの作成方法

複利システムにする方法

今回は、米ドルの口座で米ドル通貨の取引(USDJPY や USDCAD など)において、口座残高に応じて取引額を決定するといった方法を紹介します。

①レバレッジをパラメータ化する
②ロット数の計算
③例外の処理
④オーダーに変数をはめ込む

まずは、①のレバレッジですが
これの変数を Leverage としておきましょうか。

入力する場所はもうお分かりですね。わからない方は完全自動売買への道のりで復習をしてください(^^;


extern int Leverage =10;

といった感じです。今回はレバレッジ10倍でやっていきましょう。


次に②。場所はオーダーの前辺りでよいのではと思います。

1万通貨刻みで取引するのでロット数は0.1刻みになります。
その計算がこちら。

double mantuka = AccountBalance() / 10000;
int baituka = mantuka * Leverage;
double lots = baituka * 0.1 ;

今回は変数の宣言と計算を同時におこなってますよ。

まずは、
残高を取引単位の1万で割り、小数の変数 mantuka に代入します。

次に、
mantuka にレバレッジをかけて、整数の変数 baituka に代入します。
ここで変数を整数にすることによって、計算された小数点以下の値を切り捨てることになります。
ここで、何万通貨取引するか決定しましたね。

最後に、
1万通貨は0.1ロットなので、baituka に 0.1 をかけて、小数の変数 lots に代入します。これでロット数がきまりました。


しかし、③です。

計算されたロット数が、最小未満だったり最大より大きかったりした場合、オーダーを受け付けてもらえません。

なので、今回は lots が0.1ロット以下の場合は0.1ロットで、1000ロット以上の場合は1000ロットで取引するようにしましょう。

if(lots<=0.1) lots=0.1;
if(lots>=1000) lots=1000;

こうしておけば、大丈夫ですね。


そして、最後に④です。

これはもう、お分かりだと思いますが、OrderSend のカッコ内のロットを指定する箇所に変数 lots と入力すればオッケーです。


これで、複利システムは出来上がりです。


これの応用では、日本円の口座での複利システムも可能です。
例えば、USDJPY の取引では、

double mantuka = AccountBalance() / (10000*(Ask));

としておけばよいかと思います。


さらに、テクニカル指標の指数によってレバレッジを変化させることも可能ですよね。


がんばって、良いロジックをみつけましょう!!

2007年11月12日|コメント (2)トラックバック (0)

カテゴリー:EAの作成方法