ども、とのです。
世間ではお盆休みだったそうですが、
こちとらそんなものは存在しないのでひたすらお仕事です。
で、土日を使ってとあるEA作っていました。
分散のため多通貨分析
先日から4時間足-日足を利用した取引をテストしてきましたが、
日足-週足に比べてシグナルが多く出るので4通貨に限定して分析を行っていました。
しかし、4通貨だとなかなか分散ができず、
1トレードに失敗した時に他の通貨で挽回することができません。
なので、ある程度慣れてきたところで分析対象を10通貨まで増やしました。
多くのチャートを監視する限界
で、頑張って分析していたのですが、
分析がかなり大変でチャートを見る頻度が日に日に落ちていき…
ついにこの前、寝る前に発生していたシグナルを見逃す大失態(;´Д`)。
で、そういう時に限ってそのトレードが利益になってるんですよねぇ…
個人的には10通貨でも足りず、CFDを加えて30銘柄まで増やしたかったのですが、
仕事しながらそこまで面倒見るのは無理っす。
こりゃあかん…
EAに知らせてもらおう
というわけで、人間にできないことは機械にやってもらいましょう。
プログラマらしくEAを作って解決することにしました。
EAといっても自動売買ではなく、特定の条件が揃えばメールを送るだけのシステムです。
MT4にはメールを送るAPIが備わっているのでめちゃくちゃ簡単に実装できます。
プログラムの素養があれば数時間で作ることができるんじゃないでしょうか。
作ったんで備忘的解説
そんなこんなでできたのがこちら。
自分用に書いたので超汚いし色々甘いところがあると思いますが、
とりあえず動くので内容を書き留めておきます。
extern string LongTimeFrame = "D1"; extern int LongPeriodRSI =13; extern int LongPeriodStoch= 8; extern int LongPeriodSK = 5; extern int LongPeriodSD = 5; extern int LongMAMode = 0; extern string ShortTimeFrame = "Current time frame"; extern int ShortPeriodRSI =13; extern int ShortPeriodStoch= 8; extern int ShortPeriodSK = 5; extern int ShortPeriodSD = 5; extern int ShortMAMode = 0;
まずはextern変数宣言部。
長期短期2本のDTオシレーターの状態を見るので、それぞれの変数を変更できるようにしておきます。
SetVariables(); showDebug(); if (!(LongSK > 75 && LongSD > 75) && ((LongSK > LongSD)) && ShortSK_before < ShortSD_before && ShortSK_now > ShortSD_now) { MakeMessageBuy(); Mail(SIGNAL_BUY); } else if (!(LongSK < 25 && LongSD < 25) && ((LongSK < LongSD)) && ShortSK_before > ShortSD_before && ShortSK_now < ShortSD_now) { MakeMessageSell(); Mail(SIGNAL_SELL); } return(0);
色々お決まり部分をすっ飛ばしてstart関数内部。
ここで大きな流れがわかりますね。
- SetVariablesで変数を設定し、
- その変数の値が特定条件に合致すれば
- MakeMessageXXでメッセージを作成して
- Mailで送付する。
これだけです。
では個別に見ていきましょう。
iCustomを利用してDTオシレーターを呼び出す
/** * 変数の内容をセットします。 */ void SetVariables(){ LongSK = iCustom(NULL, 0, "DT Oscillator", LongTimeFrame, LongPeriodRSI, LongPeriodStoch, LongPeriodSK, LongPeriodSD, LongMAMode, 0, Current); LongSD = iCustom(NULL, 0, "DT Oscillator", LongTimeFrame, LongPeriodRSI, LongPeriodStoch, LongPeriodSK, LongPeriodSD, LongMAMode, 1, Current); ShortSK_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode,0, Current); ShortSD_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 1, Current); ShortSK_before = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 0, Current + 1); ShortSD_before = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 1, Current + 1); }
こちらがSetVariables関数です。
メールを送るかどうかの判断にはDTオシレーターが必要なので、
iCustom関数を使って呼び出します。
長期のSK,SDと、短期のSK,SDを2期間分用意します。
最後から2番目の変数がインジケーターのラインインデックスを指定しています。
0がSKで、1がSDです。
三番目の引数の"DT Oscillator"、
indicatorsフォルダに入っているファイルが"DT_Oscillator"だったりすると動作しないので気をつけましょう。
俺はこれで20分ほどハマりました。
if (!(LongSK > 75 && LongSD > 75) && ((LongSK > LongSD)) && ShortSK_before < ShortSD_before && ShortSK_now > ShortSD_now) {
上で取得した変数を利用してメール送付判断をする部分です。
こちらは買い判断をするロジックですが、
長期SKがSDより高くかつ両方が75を超えていない状態で、
短期SKがSDを上抜けた場合に買いシグナルを出します。
売りの場合はその逆です。
メールを送る
/** * 買いシグナルのメッセージを作成します。 */ void MakeMessageBuy() { title = "Buy Signal " + Symbol() + " " + Period(); message = "[Buy Signal]\n" + "[" + Symbol() + "] \n" + "Price:" + DoubleToStr(Ask, Digits) + "\n" + MakeHighLow(); }
メッセージの作成部分です。
タイトル部分には買いか売りかと銘柄、時間枠を表示し、
本文には価格を表示します。
時間枠とか価格はこの手法ではいらんのですけど、汎用的に実装しました。
string MakeHighLow() { string highLow = ""; for (int i = 1; i < 11; i++) { highLow = (highLow + "high" + i + ":" + High[i] + " low" + i + ":" + Low[i] + "\n"); } return (highLow); }
こちらはちょっと試験的に。
実際にオーダーを入れる際には1つ前のバーの高値や直近の安値を参照するため、
過去10本の高値、安値を本文に追加しています。
取引する時はiPhoneからお名前.comのサーバーにリモート接続するのですが、
リモートから価格の把握するのってすごい面倒。
その手間がなくなるのは助かります。
/** * メールを送信します。 * テストモードの時にはPrintを行います。 */ void Mail(int signal) { if (IsTesting()) { Print("Mailed. title:" + title + " message:" + message); } else { SendMail(title, message); } string name = "arrow" + i; ObjectCreate(name, OBJ_ARROW, 0, Time[1], Close[1]); if (signal == SIGNAL_BUY) { ObjectSet(name, OBJPROP_COLOR, Magenta); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_THUMBSUP); } else { ObjectSet(name, OBJPROP_COLOR, Turquoise); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_THUMBSDOWN); } i = i + 1; }
こちらがメール送信部分です。
SendMail(title, message)だけでメールが送れてしまうんです。
簡単でしょ?
MT4側でSMTPの設定が必要ですが、
設定はこちらを参考にさせていただきました。
めんどくさそうに見えて5分くらいで終わります。
バックテスト時にはメールを送る代わりにPrintを使ってログ出力だけしています。
メール送信後には、蛇足ですがチャートに矢印オブジェクトを配置しています。
おまけ:変数表示
ソースの最後にShowDebugという関数がありますが、
このEAを作っている最中にインジケーターがうまく機能していなかったので、
値を取得できているのかを判断するために作ったものです。
実際の稼働時にはコメントアウトしてしまいますが、
テスト時に表示するとこんなかんじになります。
height += 20; str = "LongSK: " + DoubleToStr(LongSK, 0); ObjectCreate("LongSK", OBJ_LABEL, 0, 0, 0); ObjectSetText("LongSK", str, 10, "Verdana", White); ObjectSet("LongSK", OBJPROP_CORNER, 0); ObjectSet("LongSK", OBJPROP_XDISTANCE, 20); ObjectSet("LongSK", OBJPROP_YDISTANCE, height);
これが1行分の処理で、strに表示したい内容書いて、
下の処理の"LongSK"を好きな名前に変更してコピペすればどんどん追加されるので便利!
以上で解説終わり。
これで沢山チャート出しても血眼になって見なくて大丈夫になりました。
ただ、一番大変なフィボナッチリトレースメント書く作業は手作業でやらないといけないんですけどね…
ここがこの手法を自動売買化できない理由でもあります。仕方ないね。
ちなみに、この手法ではDTオシレーターの変数を直近のチャートの状況に応じて最適化する必要がありますが、
それはある程度自動化できます。
そのEAについてはまた来週以降書きます。
ソース全文
#property copyright "Tono" #define SIGNAL_BUY 1 #define SIGNAL_SELL 2 extern bool SignalMail = True; extern bool EachTickMode = False; extern string LongTimeFrame = "D1"; extern int LongPeriodRSI =13; extern int LongPeriodStoch= 8; extern int LongPeriodSK = 5; extern int LongPeriodSD = 5; extern int LongMAMode = 0; extern string ShortTimeFrame = "Current time frame"; extern int ShortPeriodRSI =13; extern int ShortPeriodStoch= 8; extern int ShortPeriodSK = 5; extern int ShortPeriodSD = 5; extern int ShortMAMode = 0; int BarCount; int Current; bool TickCheck = False; string title; string message; double LongSK; double LongSD; double ShortSK_now; double ShortSD_now; double ShortSK_before; double ShortSD_before; int i = 0; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { BarCount = Bars; if (EachTickMode) Current = 0; else Current = 1; return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { if (Bars == BarCount) return(0); BarCount = Bars; //+------------------------------------------------------------------+ //| Begin | //+------------------------------------------------------------------+ SetVariables(); showDebug(); if (!(LongSK > 75 && LongSD > 75) && ((LongSK > LongSD)) && ShortSK_before < ShortSD_before && ShortSK_now > ShortSD_now) { MakeMessageBuy(); Mail(SIGNAL_BUY); } else if (!(LongSK < 25 && LongSD < 25) && ((LongSK < LongSD)) && ShortSK_before > ShortSD_before && ShortSK_now < ShortSD_now) { MakeMessageSell(); Mail(SIGNAL_SELL); } return(0); } /** * 変数の内容をセットします。 */ void SetVariables(){ LongSK = iCustom(NULL, 0, "DT Oscillator", LongTimeFrame, LongPeriodRSI, LongPeriodStoch, LongPeriodSK, LongPeriodSD, LongMAMode, 0, Current); LongSD = iCustom(NULL, 0, "DT Oscillator", LongTimeFrame, LongPeriodRSI, LongPeriodStoch, LongPeriodSK, LongPeriodSD, LongMAMode, 1, Current); ShortSK_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode,0, Current); ShortSD_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 1, Current); ShortSK_before = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 0, Current + 1); ShortSD_before = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 1, Current + 1); } /** * 買いシグナルのメッセージを作成します。 */ void MakeMessageBuy() { title = "Buy Signal " + Symbol() + " " + Period(); message = "[Buy Signal]\n" + "[" + Symbol() + "] \n" + "Price:" + DoubleToStr(Ask, Digits) + "\n" + MakeHighLow(); } /** * 売りシグナルのメッセージを作成します。 */ void MakeMessageSell() { title = "Sell Signal " + Symbol() + " " + Period(); message = "[Sell Signal]\n" + "[" + Symbol() + "] \n" + "Price:" + DoubleToStr(Ask, Digits) + "\n" + MakeHighLow(); } string MakeHighLow() { string highLow = ""; for (int i = 1; i < 11; i++) { highLow = (highLow + "high" + i + ":" + High[i] + " low" + i + ":" + Low[i] + "\n"); } return (highLow); } /** * メールを送信します。 * テストモードの時にはPrintを行います。 */ void Mail(int signal) { if (IsTesting()) { Print("Mailed. title:" + title + " message:" + message); } else { SendMail(title, message); } string name = "arrow" + i; ObjectCreate(name, OBJ_ARROW, 0, Time[1], Close[1]); if (signal == SIGNAL_BUY) { ObjectSet(name, OBJPROP_COLOR, Magenta); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_THUMBSUP); } else { ObjectSet(name, OBJPROP_COLOR, Turquoise); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_THUMBSDOWN); } i = i + 1; } void showDebug() { string str = ""; int height = 0; height += 20; str = "LongSK: " + DoubleToStr(LongSK, 0); ObjectCreate("LongSK", OBJ_LABEL, 0, 0, 0); ObjectSetText("LongSK", str, 10, "Verdana", White); ObjectSet("LongSK", OBJPROP_CORNER, 0); ObjectSet("LongSK", OBJPROP_XDISTANCE, 20); ObjectSet("LongSK", OBJPROP_YDISTANCE, height); height += 20; str = "LongSD: " + DoubleToStr(LongSD, 0); ObjectCreate("LongSD", OBJ_LABEL, 0, 0, 0); ObjectSetText("LongSD", str, 10, "Verdana", White); ObjectSet("LongSD", OBJPROP_CORNER, 0); ObjectSet("LongSD", OBJPROP_XDISTANCE, 20); ObjectSet("LongSD", OBJPROP_YDISTANCE, height); height += 20; str = "ShortSK_now: " + DoubleToStr(ShortSK_now, 0); ObjectCreate("ShortSK_now", OBJ_LABEL, 0, 0, 0); ObjectSetText("ShortSK_now", str, 10, "Verdana", White); ObjectSet("ShortSK_now", OBJPROP_CORNER, 0); ObjectSet("ShortSK_now", OBJPROP_XDISTANCE, 20); ObjectSet("ShortSK_now", OBJPROP_YDISTANCE, height); height += 20; str = "ShortSD_now: " + DoubleToStr(ShortSD_now, 0); ObjectCreate("ShortSD_now", OBJ_LABEL, 0, 0, 0); ObjectSetText("ShortSD_now", str, 10, "Verdana", White); ObjectSet("ShortSD_now", OBJPROP_CORNER, 0); ObjectSet("ShortSD_now", OBJPROP_XDISTANCE, 20); ObjectSet("ShortSD_now", OBJPROP_YDISTANCE, height); height += 20; str = "ShortSK_before: " + DoubleToStr(ShortSK_before, 0); ObjectCreate("ShortSK_before", OBJ_LABEL, 0, 0, 0); ObjectSetText("ShortSK_before", str, 10, "Verdana", White); ObjectSet("ShortSK_before", OBJPROP_CORNER, 0); ObjectSet("ShortSK_before", OBJPROP_XDISTANCE, 20); ObjectSet("ShortSK_before", OBJPROP_YDISTANCE, height); height += 20; str = "ShortSD_before: " + DoubleToStr(ShortSD_before, 0); ObjectCreate("ShortSD_before", OBJ_LABEL, 0, 0, 0); ObjectSetText("ShortSD_before", str, 10, "Verdana", White); ObjectSet("ShortSD_before", OBJPROP_CORNER, 0); ObjectSet("ShortSD_before", OBJPROP_XDISTANCE, 20); ObjectSet("ShortSD_before", OBJPROP_YDISTANCE, height); } //+------------------------------------------------------------------+
コメント