EA(自動売買)の精度を上げる方法とは?買いと売りを分類して検証
第13回では、ビジュアルモードを活用して負けやすいポイントを特定し、その苦手ポイントを克服するインジケーターを追加して精度を上げることに成功しました。
今回はさらに応用して、「買いエントリー」と「売りエントリー」で分けて、最適化を行います。
「買いエントリー」と「売りエントリー」で分けるバックテスト
これまでに作成したEAでは、「買いエントリー」と「売りエントリー」でテクニカル指標を変えずに使用してきました。
つまり、どちらも同じ期間、同じ種別の移動平均線を使用しています。
しかし、投資においては、上昇方向と下降方向の値動きを同列にしない考え方もあります。
そのため、今回は買いと売りでパラメータを分け、それぞれでバックテストを実行します。
パラメータを買いと売りで分ける
ひな形のプラグラムは前回作成したプログラムを使用します。
パラメータ部分を以下のように変更します。
input int MAGICMA = 23498721; // マジックナンバー
input double Lots =0.01; // 1ロット十万通貨単位
input int Slippage = 4; // エントリー見送りスリッページ
input double MaxSpread = 5; // エントリー見送りスプレッド
//買い設定
input double BuyTakeProfit = 5.0; // 利益確定幅(pips)
input double BuyLossCut = 20.0; // 損切確定幅(pips)
input int BuyRSIPeriod=4; // 期間(RSI)
input ENUM_APPLIED_PRICE BuyRSIAppliedPrice = PRICE_CLOSE; // 適用価格(RSI)
input int BuyUpLine = 90; // 上の線(RSI)
input int BuyDownLine = 20; // 下の線(RSI)
input int BuyMAPeriod=350; // 期間(MA)
input ENUM_APPLIED_PRICE BuyMAAppliedPrice = PRICE_CLOSE; // 適用価格(MA)
//売り設定
input double SellTakeProfit = 5.0; // 利益確定幅(pips)
input double SellLossCut = 20.0; // 損切確定幅(pips)
input int SellRSIPeriod=4; // 期間(RSI)
input ENUM_APPLIED_PRICE SellRSIAppliedPrice = PRICE_CLOSE; // 適用価格(RSI)
input int SellUpLine = 90; // 上の線(RSI)
input int SellDownLine = 20; // 下の線(RSI)
input int SellMAPeriod=350; // 期間(MA)
input ENUM_APPLIED_PRICE SellMAAppliedPrice = PRICE_CLOSE; // 適用価格(MA)
input int TradeTime = 0; // トレードを行う時間
input int NanpinWidth = 7; //ナンピンの幅(pips)
//曜日設定
input int TradeDayOfWeek = 5; // トレード曜日(1:月曜、2火曜、3:水曜、4:木曜、5:金曜)
このように、インジケーターの期間や利確、損切りpipsなどのパラメータの先頭に「Buy」「Sell」という文字列を付け、分類します。
このままだとコンパイルエラーが発生してしまうので、変更したパラメータを反映させる必要があります。
OnTick関数
まず指標部分を以下のように変更します。
//買い指標
double BuyRSI = iRSI(Symbol(), 0, BuyRSIPeriod, BuyRSIAppliedPrice, 1);
double BuyMA0 = iMA(Symbol(), Period(), BuyMAPeriod, 0, MODE_EMA, BuyRSIAppliedPrice, 0);
double BuyMA1 = iMA(Symbol(), Period(), BuyMAPeriod, 0, MODE_EMA, BuyRSIAppliedPrice, 1);
//売り指標
double SellRSI = iRSI(Symbol(), 0, SellRSIPeriod, SellRSIAppliedPrice, 1);
double SellMA0 = iMA(Symbol(), Period(), SellMAPeriod, 0, MODE_EMA, SellRSIAppliedPrice, 0);
double SellMA1 = iMA(Symbol(), Period(), SellMAPeriod, 0, MODE_EMA, SellRSIAppliedPrice, 1);
もともとの式を複製し、片方を買い用の指標に、もう一方を売り用の指標に使用します。
これでOnTick関数内の変更は完了です。
CheckForClose関数
最後はCheckForClose関数です。
こちらは利確と損切りpipsを指定している部分を書き換えます。
決済なのですでに買いと売りに分かれており、TakeProfitとLossCutをそれぞれBuyTakeProfit、SellTakeProfit、BuyLossCut、SellLossCutと変更します。
if(BuyTakeProfit <= buyProfitPips || BuyLossCut <= buyProfitPips * -1){
for( int i=OrdersTotal()-1; i>=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_BUY && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage * 10,Green);
}
}
}
}
if(SellTakeProfit <= SellProfitPips || SellLossCut <= SellProfitPips * -1){
for( int i=OrdersTotal()-1; i>=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_SELL && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage * 10,Green);
}
}
}
}
変更点はこれだけです。
バックテスト
バックテストの方法は、第12回で説明した方法と同じです。
今回は、以下のように最適化の設定をしました。
以下は、最適化を実施して、精度の高かったパラメータセットのバックテスト結果です。
売りと買いを分ける前
売りと買いを分けた後に最適化した結果
比較して分かる通り、PFを伸ばすことに成功しました。
グラフを見ると、大きなドローダウンもないように見えます。
買いと売りのエントリーポイントを分けるという方法は、今回のロジックに限らず有効です。
ぜひ他のロジックでも試してみてください。
注意点
今回のバックテストは、スプレッドを固定で行っています。
日本時間早朝の相場が緩やかになる時間帯は、スプレッドが広がりやすいという特徴があります。
実運用を行うにはスプレッド制限をかけるなど、十分注意しましょう。
プログラム全文(最適化後)
#property copyright "Copyright(C) 2023, OANDA"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
input int MAGICMA = 23498721; // マジックナンバー
input double Lots =0.01; // 1ロット十万通貨単位
input int Slippage = 4; // エントリー見送りスリッページ
input double MaxSpread = 5; // エントリー見送りスプレッド
//買い設定
input double BuyTakeProfit = 5.0; // 利益確定幅(pips)
input double BuyLossCut = 35.0; // 損切確定幅(pips)
input int BuyRSIPeriod=4; // 期間(RSI)
input ENUM_APPLIED_PRICE BuyRSIAppliedPrice = PRICE_CLOSE; // 適用価格(RSI)
input int BuyUpLine = 90; // 上の線(RSI)
input int BuyDownLine = 20; // 下の線(RSI)
input int BuyMAPeriod=550; // 期間(MA)
input ENUM_APPLIED_PRICE BuyMAAppliedPrice = PRICE_CLOSE; // 適用価格(MA)
//売り設定
input double SellTakeProfit = 40.0; // 利益確定幅(pips)
input double SellLossCut = 10.0; // 損切確定幅(pips)
input int SellRSIPeriod=10; // 期間(RSI)
input ENUM_APPLIED_PRICE SellRSIAppliedPrice = PRICE_CLOSE; // 適用価格(RSI)
input int SellUpLine = 80; // 上の線(RSI)
input int SellDownLine = 20; // 下の線(RSI)
input int SellMAPeriod=150; // 期間(MA)
input ENUM_APPLIED_PRICE SellMAAppliedPrice = PRICE_CLOSE; // 適用価格(MA)
input int TradeTime = 0; // トレードを行う時間
input int NanpinWidth = 7; //ナンピンの幅(pips)
//曜日設定
input int TradeDayOfWeek = 5; // トレード曜日(1:月曜、2火曜、3:水曜、4:木曜、5:金曜)
double dSpread;
int OnInit()
{
return(INIT_SUCCEEDED);
}
void OnTick()
{
dSpread = (Ask - Bid) / (Point * 10);
if(CalculateCurrentOrders()==0 && dSpread < MaxSpread && TimeDayOfWeek(Time[0]) != TradeDayOfWeek) CheckForOpen();
if(CalculateCurrentOrders()==1 && dSpread < MaxSpread) CheckForNanpin();
CheckForClose();
}
void CheckForOpen()
{
int res;
//買い指標
double BuyRSI = iRSI(Symbol(), 0, BuyRSIPeriod, BuyRSIAppliedPrice, 1);
double BuyMA0 = iMA(Symbol(), Period(), BuyMAPeriod, 0, MODE_EMA, BuyRSIAppliedPrice, 0);
double BuyMA1 = iMA(Symbol(), Period(), BuyMAPeriod, 0, MODE_EMA, BuyRSIAppliedPrice, 1);
//売り指標
double SellRSI = iRSI(Symbol(), 0, SellRSIPeriod, SellRSIAppliedPrice, 1);
double SellMA0 = iMA(Symbol(), Period(), SellMAPeriod, 0, MODE_EMA, SellRSIAppliedPrice, 0);
double SellMA1 = iMA(Symbol(), Period(), SellMAPeriod, 0, MODE_EMA, SellRSIAppliedPrice, 1);
if(TradeTime == TimeHour(Time[1]))
{
if(BuyRSI < BuyDownLine && BuyMA0 > BuyMA1)
{
res=OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0,"", MAGICMA, 0, Red);
}
if(SellRSI > SellUpLine && SellMA0 < SellMA1)
{
res=OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, "", MAGICMA, 0, Blue);
}
}
}
void CheckForNanpin()
{
int res;
double buyProfitPips = 0;
double SellProfitPips = 0;
for( int i=0; i<OrdersTotal(); i++ ){
if( OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
if( OrderType() == OP_BUY ){
buyProfitPips = (MarketInfo(Symbol(),MODE_BID) - OrderOpenPrice()) / (Point * 10);
break;
}else if( OrderType() == OP_SELL ){
SellProfitPips = (OrderOpenPrice() - MarketInfo(Symbol(),MODE_ASK)) / (Point * 10);
break;
}
}
}
if(SellProfitPips == 0 && buyProfitPips < NanpinWidth * -1)
{
res=OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0,"", MAGICMA, 0, Red);
}
if(buyProfitPips == 0 && SellProfitPips < NanpinWidth * -1)
{
res=OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, "", MAGICMA, 0, Blue);
}
}
void CheckForClose(){
int res;
double buyProfitPips = 0;
double SellProfitPips = 0;
for( int i=0; i<OrdersTotal(); i++ ){
if( OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
if( OrderType() == OP_BUY ){
buyProfitPips = (MarketInfo(Symbol(),MODE_BID) - OrderOpenPrice()) / (Point * 10);
}else if( OrderType() == OP_SELL ){
SellProfitPips = (OrderOpenPrice() - MarketInfo(Symbol(),MODE_ASK)) / (Point * 10);
}
}
}
if(BuyTakeProfit <= buyProfitPips || BuyLossCut <= buyProfitPips * -1){
for( int i=OrdersTotal()-1; i>=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_BUY && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage * 10,Green);
}
}
}
}
if(SellTakeProfit <= SellProfitPips || SellLossCut <= SellProfitPips * -1){
for( int i=OrdersTotal()-1; i>=0; i-- ){
if( OrderSelect(i, SELECT_BY_POS) == true ){
if( OrderType() == OP_SELL && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol() ){
res = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage * 10,Green);
}
}
}
}
}
int CalculateCurrentOrders()
{
int positions = 0;
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
{
positions++;
}
}
return positions;
}
EA(自動売買)を学びたい方へオススメコンテンツ

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。
本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。