ここでは、著書「新版 魔術師たちの心理学―トレードで生計を立てる秘訣と心構え」を参考にトム・バッソが行なったコイントストレードの実験のうち、下記の2つについてテスト用EAとして再現してみます。
・ランダムエントリー
・3倍のボラティリティ・トレーリングストップ
今回のEAコード
今回のテスト用EAの全体コードがこちらじゃ。
extern double Lots = 0.1; extern int ATR_Period = 14; extern double ATR_Multiple = 3; int OnInit() { MathSrand(GetTickCount()); // 乱数のシード設定 return(INIT_SUCCEEDED); } void OnTick() { int ticket; double sl, ts; // 保有ポジションを確認 -------------------------------- int pos_cnt = OrdersTotal(); // ATR トレーリングストップ ---------------------------- if (pos_cnt > 0) { double atr = iATR(NULL, 0, ATR_Period, 1); if (OrderSelect(0, SELECT_BY_POS) == false) return; sl = NormalizeDouble(OrderStopLoss(), Digits); if (OrderType() == OP_BUY) { ts = NormalizeDouble(Bid - atr * ATR_Multiple, Digits); if (sl == 0 || sl < ts) if (OrderModify(OrderTicket(), 0, ts, 0, 0, clrRed) == false) Print("OrderModify error."); } if (OrderType() == OP_SELL) { ts = NormalizeDouble(Ask + atr * ATR_Multiple, Digits); if (sl == 0 || sl > ts) if (OrderModify(OrderTicket(), 0, ts, 0, 0, clrRed) == false) Print("OrderModify error."); } } // エントリー------------------------------------------- if (pos_cnt == 0) { int sign = MathRand() % 1000; // 0 ~ 999 if (sign == 0) ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, 0, 0, NULL, 0, 0, clrBlue); if (sign == 1) ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 0, 0, 0, NULL, 0, 0, clrRed); } }
テスト用EA【RandomEntry_ATRtrail_EA.mq4】をダウンロード
ランダムエントリー
乱数のシードを設定
OnInit()関数内で、乱数のシードを設定します。シード値には、GetTickCount()を使用して、次のようにします。
MathSrand(GetTickCount()); // 乱数のシード設定
乱数によるシグナル判定とエントリー注文
今回は、このEAでのみポジションを保有するという前提で、ポジション有り無しをOrdersTotal()関数の値のみで判定します。
OnTick()関数内で、次のコードを追加して保有ポジションの有無を判断できるようにしておきます。
int pos_cnt = OrdersTotal();
次のコードを追加して保有ポジション無しの場合の処理を追加していきます。
if (pos_cnt == 0) { }
上記括弧内に、ランダム値(0 ~ 32,767)を返すMathRand()関数を使って、変数signが0~999の値になるように次のコードを追加します。
int sign = MathRand() % 1000; // 0 ~ 999
その下に次のコードを追加して、変数signの値が0の場合は買い注文、1の場合は売り注文をするようにします。(Lotsはパラメーターとして追加しておきます。)
if (sign == 0) ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, 0, 0, NULL, 0, 0, clrBlue); if (sign == 1) ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 0, 0, 0, NULL, 0, 0, clrRed);
ATR3倍のトレーリングストップ
パラメーターを設置
ATRの期間と、ストップ幅をATRの何倍にするかのパラメータ―を追加します。
extern int ATR_Period = 14; extern double ATR_Multiple = 3;
ATRの値によるトレーリングストップ
OnTick()関数内に、次のコードを追加してポジションを保有中の場合の処理を追加していきます。
if (pos_cnt > 0) { }
上記コードの括弧内で、ATRの値を取得します。
double atr = iATR(NULL, 0, ATR_Period, 1);
次に、保有ポジションを選択してSL値を取得します。保有ポジションが1つの場合のインデックスは0となります。(変数slとその後に出てくる変数tsは宣言しておきます。)
if (OrderSelect(0, SELECT_BY_POS) == false) return; sl = NormalizeDouble(OrderStopLoss(), Digits);
買いポジション保有中のトレーリングストップ処理を次のようにします。
if (OrderType() == OP_BUY) { ts = NormalizeDouble(Bid - atr * ATR_Multiple, Digits); if (sl == 0 || sl < ts) if (OrderModify(OrderTicket(), 0, ts, 0, 0, clrRed) == false) Print("OrderModify error."); }
売りポジション保有中のトレーリングストップ処理も同じ要領で追加します。
if (OrderType() == OP_SELL) { ts = NormalizeDouble(Ask + atr * ATR_Multiple, Digits); if (sl == 0 || sl > ts) if (OrderModify(OrderTicket(), 0, ts, 0, 0, clrRed) == false) Print("OrderModify error."); }
感想
早速、バックテストをしてみたのですが、ATRの期間を14くらいにするとよさそうな感じでした。
また、取引機会を増やそうと1時間足で試してみましたが、ATRの3倍だとすぐにノイズにやられてしまうので、4.5倍あたりがよさそうな感じでした。
トレンドフォローのストップの目安になりそうですね!
では、今回はこのへんで。
初めまして。
いつも楽しく拝見させていただいてます。
早速、魔術師たちの心理学を読ませて
いただいてます。
こんなロジックが可能かご相談させていただきたいのですが。
OrderSendで注文した際に、損切値を設定し、その損切値で自動決済されてしまった、
その直後に逆ポジションを自動的に立てるようなロジックを作ることは可能でしょうか。。
マーサーさん
こんばんわ。
魔術師たちの心理学は解読が難しいですが、すごく役に立ちますよね!
(新版は翻訳も改良されたそうですが^^;)
「OrderSendで注文した際に、損切値を設定し、その損切値で自動決済されてしまった、 その直後に逆ポジションを自動的に立てるようなロジック」
ですが、
extern int StopLoss=50;
int lasttype;
double laststop=0;
int start()
{
if(買い条件) int sign=1;
if(売り条件) sign=-1;
if(OrdersTotal()=laststop))
{
OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, Ask-StopLoss*Point, 0, NULL, 0, 0, Blue);
lasttype=1;
laststop=Ask-StopLoss*Point;
}
if((laststop==0 && sign==-1) || (laststop!=0 && lasttype==1 && Bid<=laststop))
{
OrderSend(Symbol(), OP_SELL, 0.1, Bid, 3, Bid+StopLoss*Point, 0, NULL, 0, 0, Red);
lasttype=-1;
laststop=Bid+StopLoss*Point;
}
}
else
{
if(手仕舞い条件)
{
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, Blue);
laststop=0;
}
}
return(0);
}
というように、記憶用の変数を使って、場合分けをしてみてはどうでしょう?
また、利食い値も設定するなら、その記憶用の変数も作って、先にポジションがない場合で利食い値に達しているときlaststopを0にするというコードも加えればよさそうです。
また、コメントお待ちしております!
早速のコメント、感激です。
なるほど、start()の前に、変数を作って
損切値を保存しておけば良かったのですね!
ありがとうございます。
度々、素人質問で恐縮ですが、
OrderSendで、損切値+スリップページを設定していたにもかかわらず、
急落した為に、損切りできなくなってしまった場合、
その時のOrderSendの注文は、未約定注文として残ってしまうのですか?
マーサーさん
ストップを設定してあるポジションが、急落時にクローズされなかった経験がないので断言できませんが、ストップ値に達しているものは、何度もクローズしようとすると思います。
また、OrderSendで新たにポジションを取る場合に約定されなかった場合は、エラーとなり、未約定というより不約定といった感じでしょうか^^;
そして、また注文の条件になっている場合はオーダーするといった感じだと思います。
慶次さま
度々のコメントありがとうございます。
急落時にクローズできなかった時に、
OrderModifyで繰り返し損切値を更新するのが良いのか、
スリップページを大きめにして対応するのが良いのか、と思いまして。
スリップページを大きめにしても、急落時に対応できない時は、万が一に備えて、OrderModifyで損切値を更新するロジック作っておく必要は、あるのでしょうか。。
トレイリングストップでOrderModifyするロジックは見かけても、万が一に備えて損切値を更新する処理を見たことがなかったので、どうされているのかと思いまして。。
よろしくお願いいたします。紹介していただい SpearmanRankCorr は著作権フリーでしょうか?商材の フィルターで一部使用するのですが・・。おわかりになりましたら よろしくお願いいたします。
マーサーさん
損切り値を更新する必要はないと思いますよ!
はじめましてさん
すみません。SpearmanRankCorrの著作権はわかりません^^;
なんか、偉人さんと言うか、他の方は色々な手法を考え付かれるんですねぇ^^
その考え方に感服します、ホントに。
結局そういったことを考え付く人が、本当に上手くいく人なんでしょうね。
参考になります。
えぎさん
こんばんわ。
そうですね~!
良いアイデアを参考に良いシステム作り
がんばりましょう!