#FXトレード戦略No.8: 年初連続2回の損切りを調べてみた

 

 

こんにちは。

こちら ⬇️ のマガジンでご紹介している『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を運用しています。

今年の2週目までの実績をこちらでご紹介していますが、EURJPYは1・2週目連続で損切りが発生し、おおきなマイナスからの出発となりました。

下の画像の赤枠の部分です。
この2回連続の損切りは、新年の1週目、2週目の全く同じタイミング、NewYork時間の水曜日 21:40分、日本時間の木曜日 11:40分のエントリーです。
この記事では、この2連続LOSSからなにか学ぶことができるのか、私なりにデータから分析をしてみました。
その内容を共有いたします。

画像

損切りの状況をチャートで確認

まず、チャート上での推移を確認します。

画像
1分足(GMT+2) 1/2(木曜) 11:40分(日本時間)エントリー
画像
1分足(GMT+2) 1/9(木曜) 11:40分(日本時間)エントリー
画像
15分足

どちらのチャートでもエントリーから一律の下げとなり、損切りで終わりました。
チャート上からはこのタイミングでのエントリーは完全にNGです。

2023~2024年の同タイミングでの為替の動きを確認すると、1/2は下げトレンドとなることが多く、分が悪そうです。
1/9日は上げ基調となることが多く、損切りはなさそうです。

画像
2024/1/2~1/9前後 (GMT+2時間)
画像
2023/1/2~1/9前後 (GMT+2時間)

チャートからは、一旦 1/2はNG、1/9はOKと考えます。

特定タイミングに限定した分析

2007年以降のヒストリカルデータでは、どういう結果になるのかバックテストを利用して確認します。
ストラテジーテスターで1月、水曜日、NewYork時間21:40に限定してバックテストをしてみた結果がこちらです。
ちなみに、85戦の内の一回の負けは、2013年の1/2日でした。
勝率 98.82%で全く問題ありません。

画像

ここまでの結果のみで判断すると、1/2を含め 1月水曜日 21:40のエントリーは有効であると考えられます。

さて、ここでもう一歩踏み込んで分析してみたいと思います。
ここまでの分析の観点は、勝ち負けが基準になっていました。
次に、エントリー後の決済までの経過時間、ポジション保有時間の観点で分析します。
簡易的にエントリー後120分以内に決済できなかったものを負けとして、その勝敗を基準に考えてみます。

120分としたのは私が感覚的に決めたものですが、利小損大戦略では一日数回のエントリーが想定されているので、ポジション保有時間が長くなると、次のエントリーがされず、機会損失になります。
この戦略では、より短期に決済することがベターであり、また、不確定要素によるリスクを避けるという観点でもポジション保有時間は短くしたほうがいいはずです。

ポジション保有時間が120分を超過したかどうかを基準にバックテストの結果を集計すると以下の通りになりました。

画像

1列名の月内週目というのは、何週目かという意味です。
全体85件の内、決済が120分超となったものは1~5週目まで、4, 4, 3, 2, 2件だったという結果です。
最終列の黄色の部分が、各週の全体件数に対する負け(決済が120分超過)したものの割合です。
全体がたったの85件なので統計的な傾向であるとするのは問題ありと言われるかもしれません。
ただし、早めの週、特に1週目に関してはポジション保有時間が長めになる結果となっています。

この傾向が水曜日に限定されるのか、木曜日のエントリーでも確認してみます。
同じNew York時間の 21時台ですが、エントリー時間は少し異なります。
木曜日のエントリーでは2007年以降は全勝しています。

画像

ポジション保有時間での勝ち負けを集計してみると以下の通りでした。

画像

水曜日に比較するとかなり平準化されています。
ヒストリカルデータから確認できる傾向としては、1月水曜日の1~2週目、特に1週目は損切り、および、ポジション保有時間が長くなる傾向があるのではないかと考えます。

FXトレード戦略への反映

さて、ここまで分析を進めてきましたが、この結果をどうFXトレード戦略に反映すればいいのでしょうか。

実は今回の結果によるFXトレード戦略の変更はありません。
理由は、以下の記事でご紹介した戦略の改善ですでに同等の対応がされているからです。

この戦略の改善では、特定の日付(および曜日)で勝率への影響があるものを確認し、影響度合いにより除外をするという対応をしました。
今回、確認できた1月1週目の水曜については、この対応の中ですでに除外していたため、追加の対応はいりません。

同じような分析をやっただけと思われるかもしれませんが、今回の分析の観点は全く新しいものであり、FXトレード戦略の運用をより安定化するものになるのではないかと考えます。
勝率については十分なレベルを達成できているので、今後の戦略の改善点は『安定化』がキーワードになると思っています。
エントリー後、短時間での利確が増えるほど、より安定したトレードになり、メンタル的にも安心な運用ができると思います。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。



#FXトレード戦略
#MT4
#勝率
#EURUSD
#eurjpy
#フォワードテスト
#FXTF
#利小損大
#利小損大戦略
#利小損大戦略で勝ち抜く

#FXトレード戦略No.7: 利小損大戦略B ストキャスティクス版たたき台 勝率 ⇒ 91.17%

見出し画像

 

 

こんにちは。

こちら ⬇️ のマガジンでご紹介している『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を運用しています。

EURUSDは、今年はまだ負けなし24連勝中で順調です。

この記事は、利小損大戦略のPlan Bとしてストキャステックスを利用したトレード戦略について共有いたします。

◾背景

ストキャステックスとは何といった基礎的なことは、こちらの記事をご参照ください。

これまで作成してきた利小損大のトレード戦略は、勝てるタイミングをヒストリカルデータから抽出し、その勝てるタイミングでのみエントリーするという非常にシンプルなトレード方法でした。
この利小損大戦略は、タイミング以外にも適用できると考えています。
その一つとして、メジャーなオシレータ系の指標であるストキャステックスをベースとしてトレード戦略を検討したいと以前から思っていました。

こういった指標を利用したトレードルールを作成するのは初めてなのですが、実際にトライしてみたところ初版のたたき台としては以外にいい感じにできました。
まだまだ粗削りでこれからさらに精緻化、改善する余地があるものですが、物になりそうな感触を感じています。

現段階のものをそのままご紹介したいと思います。
ゆくゆくは、現在運用しているタイミング系利小損大戦略と並ぶ、FX運用の柱となるFXトレード戦略として発展させていきたいと思います。

◾今回作成した戦略の概要

今回作成した戦略も非常にシンプルではあります。
タイミングの代わりに、ストキャステックスが示すエントリーのタイミングで利確を少なく、損切りを大きくした売買を行うというものです。

実際のパラメータは以下のとおりです。

// 入力パラメータ
extern int K_Period = 26;          // %K期間
extern int D_Period = 6;           // %D期間
extern int Slowing = 6;            // スローイング期間
extern double LotSize = 0.1;       // 取引ロットサイズ
extern int StopLoss = 250;         // ストップロス(ポイント)
extern int TakeProfit = 25;        // テイクプロフィット(ポイント)
copy

利確と損切りの割合が 25 : 250、リスクリワード 0.1になります。
勝率が92%ぐらいになれば、トータルで勝てるイメージです。

今回は、最初のたたき台ということで作成したトレードルールで勝率91%を超えてきました。
今後の改善により十分ものになるものになりそうです。

たたき台のバックテスト結果

実際に作成したトレードルールを過去10年分のEURUSDデータにてバックテストを行った結果がこちらになります。

  • 勝率 91.17%   PF  1.39   最大DD 2.79%

画像
画像

現在運用しているタイミング系利小損大戦略と比べるとかなり見劣りするように見えると思います。
しかし、現時点でほとんどパラメータ調整、最適化を実施していないことを考えると、非常に可能性が高いと考えています。
今後、さらなる改善を行い、別記事にてご紹介したいと思います。
ご期待ください。

参考までに、現時点でのEAコードを共有いたします。

#define MAGIC_NUMBER 111222333           // 任意の一意の番号

// 入力パラメータ
extern int K_Period = 26;          // %K期間
extern int D_Period = 6;           // %D期間
extern int Slowing = 6;            // スローイング期間
extern double LotSize = 0.1;       // 取引ロットサイズ
extern int StopLoss = 250;         // ストップロス(ポイント)
extern int TakeProfit = 25;        // テイクプロフィット(ポイント)

// グローバル変数
bool canTrade = true;

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    if(!canTrade) return;
    
    // ストキャスティクスの値を取得
    double kValue0 = iStochastic(Symbol(), 0, K_Period, D_Period, Slowing, MODE_SMA, 0, MODE_MAIN, 0);
    double dValue0 = iStochastic(Symbol(), 0, K_Period, D_Period, Slowing, MODE_SMA, 0, MODE_SIGNAL, 0);
    double kValue1 = iStochastic(Symbol(), 0, K_Period, D_Period, Slowing, MODE_SMA, 0, MODE_MAIN, 1);
    double dValue1 = iStochastic(Symbol(), 0, K_Period, D_Period, Slowing, MODE_SMA, 0, MODE_SIGNAL, 1);
    
    // クロス判定とトレード
    if(kValue0 > 89 && dValue0 > 89) // オーバーボーght域
    {
        if(kValue1 <= dValue1 && kValue0 > dValue0) // ゴールデンクロス
        {
            //OpenSell();
        }
    }
    else if(kValue0 < 11 && dValue0 < 11) // オーバーソールド域
    {
        if(kValue1 >= dValue1 && kValue0 < dValue0) // デッドクロス
        {
            OpenBuy();
        }
    }
    
    CheckTakeProfit();

}

//+------------------------------------------------------------------+
//| 買いポジションを開く                                              |
//+------------------------------------------------------------------+
// 最小ストップ距離を考慮したSL/TP設定の例
void OpenBuy()
{
    double minDistance = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    
    // ストップロスの計算
    double sl = Ask - StopLoss * Point;
    if(Ask - sl < minDistance)
        sl = Ask - minDistance;
        
    // テイクプロフィットの計算
    double tp = Ask + TakeProfit * Point;
    if(tp - Ask < minDistance)
        tp = Ask + minDistance;
    
    int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp, "Buy Order", MAGIC_NUMBER, 0, clrGreen);
    
    if(ticket >= 0)
    {
        Print("OrderSend failed with error #", GetLastError());
    }
}


//+------------------------------------------------------------------+
//| 売りポジションを開く                                              |
//+------------------------------------------------------------------+
void OpenSell()
{
    double minDistance = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
    
    // ストップロスの計算
    double sl = Bid + StopLoss * Point;
    if(sl - Bid < minDistance)
        sl = Bid + minDistance;
        
    // テイクプロフィットの計算
    double tp = Bid - TakeProfit * Point;
    if(Bid - tp < minDistance)
        tp = Bid - minDistance;
    
    int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp, "Sell Order", MAGIC_NUMBER, 0, clrRed);
    
    if(ticket < 0)
    {
        Print("OrderSend failed with error #", GetLastError());
    }
}

//+------------------------------------------------------------------+
//| Check Take Profit Function                                       |
//+------------------------------------------------------------------+
void CheckTakeProfit() {
   //DEBUG Print(">>> CheckTakeProfit()");

    for (int i = OrdersTotal() - 1; i >= 0; i--) {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if (OrderType() == OP_BUY && OrderMagicNumber() == MAGIC_NUMBER) {
                double entryPrice = OrderOpenPrice();
                double targetPrice = entryPrice + TakeProfit * Point;

                // 現在価格が利確目標に到達した場合
                if (Bid >= targetPrice) {
                    CloseOrder(OrderTicket());
                    Print(">> Order closed by Take Profit");
                }
            }
        }
    }

   //DEBUG Print(">>> CheckTakeProfit() ended........");
}

//+------------------------------------------------------------------+
//| Close Order Function                                             |
//+------------------------------------------------------------------+
void CloseOrder(int ticket) {
   //DEBUG Print(">>> CloseOrder()");

    if (OrderSelect(ticket, SELECT_BY_TICKET) && OrderType() == OP_BUY) {
        double closePrice = Bid;
        bool result = OrderClose(ticket, OrderLots(), closePrice, 2, clrRed);
        if (result) {
            //DEBUG Print("Order closed: ", ticket);
        } else {
            //DEBUG Print("Error closing order: ", GetLastError());
        }
    }

   //DEBUG Print(">>> CloseOrder()  ended.....");
}

//--------------------------------------------------------------
// The handler of the event of completion of another test pass:
//--------------------------------------------------------------
double OnTester()
{
   double trades = TesterStatistics(STAT_TRADES);
   double win = TesterStatistics(STAT_PROFIT_TRADES);
   double winratio = 0;
   if(trades>0) winratio = NormalizeDouble(win/trades*100,2);

   return(winratio);
}
copy

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。

#FXトレード戦略No.6: 利小損大戦略 EURUSDの勝率を改善⇒99.03%~99.21%

見出し画像

 

 

こんにちは。

こちら ⬇️ のマガジンでご紹介している『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を運用しています。

EURUSDは、12月半ばまで損切が多めで不調でしたが、その後EURJPYよりも安定した結果となっています。
バックテストでも勝率ではEURUSDの方が安定して高めであったため、順当な結果と考えることもできます。

画像

この記事は、以下⬇️ の記事でご紹介したEURJPYの勝率の改善の続編として、EURUSDの勝率改善を実施したので、その結果のご紹介です。

◾背景

EURJPYに関して12月・1月データの勝率の改善を行いました。

EURJPYの時と同様に、特定の日付、および曜日ごとに勝率に影響するものを特定し、エントリーから除外により改善が期待できるものを選別していきます。
過去10年以上のデータであっても、条件が細かくなると対象データ数が少なくなるので、判断が難しいものが多いです。

オーバーフィッテングと言われる問題にならいよう注意する必要があります。

◾戦略改善の結果

EURJPYとEURUSDでは、損切りとなるケースは全く異なります。
ただし、1月に限って言えばどちらも 初日の取引である1月2日は損切りとなる割合が高いです。

画像
EURJPY 1/2日の取引結果
画像
EURUSD 1/2日の取引結果

一部、曜日ごとの影響度合いなども考え、除外ルールを定義しました。
その結果、EURUSDの12月~1月分について、以下の結果となりました。

  • 12月データ  勝率 98.29%  ⇒  99.21% 

  • 1月データ  勝率 98.14%  ⇒  99.03% 

画像
最適化結果

上記のストラテジーテスターの最適化結果で表示されている「Ontester結果」が勝率です。
EntryExcludes=-1となっているのが除外ルール適用前、EntryExcludes=0となっているのが除外ルール適用後で、今回の改善の結果です。
1月、12月ともに99%を超えました。

画像
改善後の12月データのバックテスト結果
画像
改善後の1月データのバックテスト結果


なお、今回のEURUSDのエントリー除外ルールでは、1/20はエントリーから除外されません。
が、トランプ大統領の就任にあたり相場が荒れそうなので、来週1/20~21は運用を停止する予定です。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。



#FXトレード戦略
#MT4
#勝率
#EURUSD
#eurjpy
#フォワードテスト
#FXTF
#利小損大
#利小損大戦略
#利小損大戦略で勝ち抜く

#FXトレード戦略No.5: 利小損大戦略 EURJPYの勝率を改善⇒97.69%~99.07%

見出し画像

 

こんにちは。

こちら ⬇️ のマガジンでご紹介している『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を運用しています。
駆け足で進めてきましたが、12月からロットを少し増やしました。

この記事では、EURJPYについて勝率の改善を実施したのでその結果についての紹介になります。
改善前の勝率については、こちら ⬇️ の記事でご紹介しています。

◾背景

EURJPYに関しては12月から運用を開始し、12月はとてもいい感じで運用できていました。
しかし、年末最終日と年明け初日の取引では損切りとなり、トータルでは若干のプラス、今年(といっても1週間程度)はマイナス圏に落ち込んでいます。

画像

現時点で71勝4敗(勝率94.67%)と、バックテストで確認した勝率を大きく外している感じです。
年末年始の損切りが多発したことが理由ですが、その点も含めて改めて分析、勝率の改善を行いました。

◾戦略改善の観点と結果

今回の戦略の改善は、特定の日付という観点で改善を行いました。
例えば、12月の31日に絞った場合の勝率を確認し、エントリーから除外するといった感じです。
特定の日付に加え月の何週目か、また、曜日との組み合わせでも検討しました。
ただし、条件を組み合わせると対象のデータが限定されすぎるため、有効性の判断がつけづらくなります。
そのため、基本的には日付ごとに勝率がどの程度を確認し、とびぬけて悪い
ものを除くという対応を行いました。

その結果、12月~1月分については以下の結果となり、勝率のさらなる改善となっています。
1月分については、勝率が99%を超えてきました。

  • 12月データ 

    • (改善前)勝率 97.36% 、PF 3.27、最大DD 1.10%

    • (改善後)勝率 97.69% 、PF 3.71、最大DD 1.10%

画像
画像
  • 1月データ

    • (改善前)勝率 98.27% 、PF 5.21、最大DD 1.06%

    • 改善後勝率 99.07% 、PF 10.89、最大DD 1.21%

画像
画像

今回の改善の結果、1月の勝率が99%を超え、平均連勝数がなんと96に伸びました。
平行して運用しているEURUSDはバックテストではEURJPYよりも高い勝率となっていました。
実運用でも12月後半からは非常に安定した動きを見せてくれています。

EURJPYも今回の改善により、より安定した動きとなるか、実運用での結果を確認していきたいと思います。

なお、今回の分析により1/20はエントリーから除外されます。
元々、トランプ大統領の就任にあたり相場が荒れると思っており、運用を停止しようと思っていたので、ちょうどいいタイミングでした。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。



#FXトレード戦略
#MT4
#勝率
#EURUSD
#eurjpy
#フォワードテスト
#FXTF
#利小損大
#利小損大戦略
#利小損大戦略で勝ち抜く

【速報】利小損大・FXトレード戦略の取引結果 1/2-1/10(今年初、1-2週)

画像12025年初 EURJPYは損切り2連チャン。一方、EURUSDは安定。EURJPYは年末・年初はお休みするのが無難のようです。
画像2EURJPYはマイナスに落ち込みました。EURUSDは問題なし。
画像3デモ口座も年初は損切り2連チャンとなり同様。
画像4デモでは損益pipsはあまり参考になりません。
画像5EURJPYの年末最終日、年初初日は取引なしとした方がベターですね。再度データ分析の上、ルールを手直し予定。
画像6EURUSDは年末年始も比較的安定していましたが、1/2はポジション保有時間が長めでした。

利小損大トレード戦略の優位性について

見出し画像

あけましておめでとうございます。

今年の一つの目標として、去年末から運用開始した利小損大戦略のFXトレードをより確実な運用成果を生み出すビジネスとして確立したいと思います。
この記事では、このビジネス(=トレード戦略)の優位性を再確認し、共有したいと思います。

このトレード戦略については、こちらのマガジンでこれまでの経過をご覧いただけますので参照ください。

このトレード戦略を始めた背景

まず、なぜ私がこのFXトレードを始めたのか、その経緯についてご紹介します。

私は、10年以上前から金・銀CFDのグリッドトレード(リピート売買)を運用してきました。
その運用での一番の悩みが含み損の拡大です。
グリッドトレードの相場の波を取るという発想は非常に好きなのですが、想定範囲を外れてきた場合に含み損が拡大する点が非常に難しいなと感じています。
外れてきた場合の含み損の拡大に対処する有効な手段がなく、リスクを下げたいにも拘わらず、どんどん含み損が拡大していくのはメンタル的なストレスが非常に高く、中長期に運用していく上での大きな難点でした。
特に、運用資金を拡大していく場合、比例して含み損も倍増していきます。
すでに拡大してしまった含み損からは有効な逃げ道がない、これを何とかしたいとずっと考えていました。

そんなある時、FXで特定の時間帯のエントリーで微小の利確を薦めている方がいることを知り、ちょっと自分でもやってみようという気になったのがきっかけです。
MT4を見よう見まねで使い始めバックテストをやってみると確かに非常に高い勝率を実現できる条件があり、それを発展させて現在運用しているようなFXトレードルールにつながっています。

小利損大戦略の優位性

この戦略の優位性・メリットについては以下のように考えています。

  • 高い勝率でコツコツと利益を積み重ねるため、メンタルの負担がすくない

  • 一日数回のエントリーできわめてシンプル、難しさがない

  • 相場観が不要で、日々相場の動きを監視する必要がない

  • 資金に応じた1ポジション・翌日持ち越しなしのため、リスク管理・資金管理が不要

  • 再現性が極めて高く、かつ、運用資金を拡大しても戦略の変更なし

特に、一般的なリピート取引と比較した場の優位性は、上記の黒字で示した部分です。
つまり、非常に効率よくリスクをコントロールできる点です。
具体的には、例えばEURUSDの取引をする場合、1万通貨で必要となる資金は10万円程度です。
この10万には、証拠金として必要な6万強と損切り発生2~3回程度の損失分が含まれます。
仮に大きな相場変動があり、損切りが連続3回ほど発生したとしても、4万程度の損失で一時撤退することができます。
そもそもその状況にれば、早めの損切りにより損失を最小限に食い止めることができます。
デイトレと同じで日々仕切り直す戦略なので、取り返しのつかない損失というのはありません。

また、このリスク・コントロールのし易さに加え、この戦略が生み出す利益は同じ資金量に対し、金・銀CFDリピート取引の5倍以上の可能性があります。
金銀リピートが月間2%の利益だとした場合、月間10%以上の利益を生み出す可能性が十分にあるのではないかと考えています。
この点については、これまでのバックテストでの結果から推定になりますが、今後の運用で実績を確認していきます。

パートナー募集

この記事でご紹介した『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を一緒に改善し、より強固なビジネスにするために協力いただけるパートナーの募集を開始いたしました。
FXの経験などは問いませんが、この戦略がなにか面白いことになりそうだ、失敗してもいいからやってみようかなという方はせびこちらのパートナー募集の記事をご覧ください。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。

FXトレードMT4運用のモバイル通知(Discord)の設定方法

見出し画像

こんにちは。

FXトレード戦略の本番環境でのフォワードテストを実施しています。
モバイルでのモニタリングのためこちら ↓ の記事で MT4アプリの活用をご紹介しました。

この記事では、モニタリングをさらに改善した私のやり方について共有いたします。
Discordへメッセージ、および、チャート画像の送信をするというものです。

背景

『高い勝率で利小損大』を乗り切る方針のFXトレード戦略を作成・運用しています。
『損小利大』とは全く逆の戦略です。

このトレードの運用を始めたばかりなので、しっかりモニタリングをする必要があります。
先日の記事でMT4アプリを利用したモバイルでのモニタリングが非常にいい感じにできることをご紹介しました。
実際にモニタリングを行ったところ、いくつか改善点がでてきました。
今回は、この改善のために私が実施した内容、スクリプトを共有いたします。
アプリ、ツールなどは利用せず直接EAスクリプトを修正する方法です。
この改善により、以下のようなイベント発生時にイベント時のマーケット情報、また、チャート情報を即時に通知されるようにできます。

  • 買いエントリーイベント

  • スプレッドが広く、エントリーをスキップした際の通知

  • 利確ポイント発生による売却イベント

  • ポジション保持時間による手仕舞いの売却イベント

今回、LINEではなく Discordにした理由は以下の二つあります。

ということで、Discordでの通知をすることにしました。
"MT4  Discord  通知"でネット検索すると、いろいろと情報がでてきます。
私がみた限りでは有償のツールを前提とするものが多く、かつ、あまり柔軟に変更できるようなものはありませんでした。
また、多くのツールではインジケーター利用が前提となっていました。
私はEAスクリプトみで自動取引をしており、インジケーターを利用せず直接EAスクリプトに仕込む形での実装しました。
実装にあたり、あまり参考になりブログ、ネット情報がなかったため、AIに相談しながらやりましたが、チャート画像の連携部分で非常に苦労しました。

MT4 EAからのDiscord通知の事前準備

事前準備として、以下の設定を準備していただく必要があります。
この記事では、事前準備の詳細は省きますが、ネット検索にて必要な設定などは確認できるかと思います。

  • DiscordのWebhook URL発行

  • MT4の通知許可を設定

二点目のMT4通知許可については、➀ツール > オプション > エキスパートアドバイザ画面での設定と②チャートに仕込んだEAの設定の二か所あるのでご注意ください。

Discord通知するEAスクリプト例 

実際のスクリプトは、OrderSend()などイベント発生の中でDiscord通知を呼び出すトリガー部分とその呼び出しにより、実際にDiscordに連携する部分に分かれます。

私が利用しているスクリプトをベースにご自身の要望に合わせて手直しをしていただければいいかと思います。
AIを活用して修正することもできると思いますが、EAスクリプト言語Pythonなどに比べるとAIから提案されるコードはそれほど品質が高くないのでご注意ください。

トリガー側の例

SendInfoAndChartToDiscord()が呼び出し部分です。

   string msg; 

   if (spreadInPips <= maxSpreadInPips ) {
      ticket = OrderSend(Symbol(), OP_BUY, lotSize, askPrice, 2, stopLossPrice, takeProfitPrice, "SimpleEA Buy", MAGIC_NUMBER, 0, clrGreen);
      if (ticket < 0) {
          Print("## Error opening buy order: ", GetLastError());
      } else {
          Print("## Buy order opened: ", ticket, 
          " NY時間: ", TimeToString(NYTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS), " spread= ", spreadInPips);

          msg = "[買いエントリー発生] price=" + askPrice + " tp=" + takeProfitPrice + " spread=" + spreadInPips + "\n";
          SendInfoAndChartToDiscord(msg);
      }
   }
copy


Discord呼び出し側の例

このままコピペで利用いただくこともできるかと思います。
webhook_url の XXXXXXXXX部分のみご自身で準備した webhook URLに変更してください。
また、SendChartImage()、AlertDiscord()を個別に呼び出し、テキストメッセージのみ、または、チャート画像のみを個別に送信・通知することもできますので、必要に応じ手直しください。

//#########################################################################################
// Discord Webhook URL
input string webhook_url = "https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

//+------------------------------------------------------------------+
//| 市場情報を取得                                                    |
//+------------------------------------------------------------------+
string GetMarketInfo()
{
    string info = "\n";
    
    // 基本情報
    info += "Symbol: " + Symbol() + "\n";
    info += "Time: " + TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS) + "\n";
    
    // 価格情報
    double bid = MarketInfo(Symbol(), MODE_BID);
    double ask = MarketInfo(Symbol(), MODE_ASK);
    double spread = (ask - bid) / Point;
    
    info += "Bid: " + DoubleToString(bid, Digits) + "\n";
    info += "Ask: " + DoubleToString(ask, Digits) + "\n";
    info += "Spread: " + DoubleToString(spread, 1) + " pips\n\n";
    
    // 日足情報
    info += "Daily Stats:\n";
    info += "High: " + DoubleToString(iHigh(Symbol(), PERIOD_D1, 0), Digits) + "\n";
    info += "Low: " + DoubleToString(iLow(Symbol(), PERIOD_D1, 0), Digits) + "\n";
    double daily_range = (iHigh(Symbol(), PERIOD_D1, 0) - iLow(Symbol(), PERIOD_D1, 0)) / Point;
    info += "Range: " + DoubleToString(daily_range, 1) + " pips\n";
    
    return info;
}

//+------------------------------------------------------------------+
//| チャート画像を保存して送信                                        |
//+------------------------------------------------------------------+
bool SendChartImage()
{
    string filename = "chart_" + Symbol() + "_" + TimeToStr(TimeLocal(), TIME_DATE|TIME_SECONDS) + ".png";
    StringReplace(filename, ":", "-");
    StringReplace(filename, " ", "_");

    if(!ChartScreenShot(0, filename, 460, 320, ALIGN_RIGHT))
    {
        Print("## スクリーンショットの取得エラー");
        return false;
    }
    
    //string file_path = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL4\\Files\\" + filename;
    //int file_handle = FileOpen(file_path, FILE_READ|FILE_BIN);
    int file_handle = FileOpen(filename, FILE_READ|FILE_BIN);
    if(file_handle == INVALID_HANDLE)
    {
        Print("## ファイルオープンエラー。 Error code: ", GetLastError());
        return false;
    }
    
    int file_size = FileSize(file_handle);
    uchar file_data[];
    ArrayResize(file_data, file_size);
    FileReadArray(file_handle, file_data, 0, file_size);
    FileClose(file_handle);
    
    string boundary = "---------------------------" + IntegerToString(TimeLocal());
    
    string headers = "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n";
    
    string data = "";
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n";
    data += "Content-Type: image/png\r\n\r\n";
    
    uchar post_data[];
    StringToCharArray(data, post_data, 0, StringLen(data), CP_UTF8);
    ArrayCopy(post_data, file_data, ArraySize(post_data));
    
    string end_boundary = "\r\n--" + boundary + "--\r\n";
    uchar end_data[];
    StringToCharArray(end_boundary, end_data, 0, StringLen(end_boundary), CP_UTF8);
    ArrayCopy(post_data, end_data, ArraySize(post_data));
    
    char result[];
    string result_headers;
    
    ResetLastError();
    int res = WebRequest(
        "POST",
        webhook_url,
        headers,
        5000,
        post_data,
        result,
        result_headers
    );
    
    FileDelete(filename);
    
    if(res == -1)
    {
        Print("## WebRequestエラー: ", GetLastError());
        return false;
    }
    
    return true;
}

//+------------------------------------------------------------------+
//| Discord通知関数                                                   |
//+------------------------------------------------------------------+
bool AlertDiscord(const string url, const string text)
{
    int status_code;
    string headers;
    char data[];
    char result[];
    
    StringToCharArray("content=" + text, data, 0, WHOLE_ARRAY, CP_UTF8);
    
    status_code = WebRequest("POST", url, NULL, NULL, 5000, data, 0, result, headers);
   
    if(status_code == -1)
    {
        Print(GetLastError());
        return(false);
    }
    
    return(true);
}

bool SendInfoAndChartToDiscord(string title)
{
   if(IsTesting()
    || (AccountInfoInteger(ACCOUNT_TRADE_MODE) != ACCOUNT_TRADE_MODE_REAL)
   ) return(false);
    
   string msg;
   
   // Discordに通知
   msg = "```\n"; // Discordのコードブロック形式
   msg += "実行EA:" + WindowExpertName() + "\n";
   msg += title + "\n";
   msg += GetMarketInfo();
   msg += "```";
 
   AlertDiscord(webhook_url, msg);
 
   // チャート画像を送信
   SendChartImage();
   
   return true;
}
copy

コードの詳細説明は省きますが、質問などはコメントいただければ、できるだけ回答いたします。

Discord通知の例

Discord側に送られてくる通知イメージの例は以下のとおりです。

画像

なかなかいい感じに通知が届くようなりました。
これで、モバイルでのモニタリングは非常に快適になり、FXトレードの成果にもつながることを期待したいと思います。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。