はじめに
ここでは、当ブログで扱ってきたインジケータや手法を利用したEAのサンプルソースを一覧で紹介しています。
EAの有効性をプロフィットファクターの値で判定しています。また、難易度はプログラミングに要するの難易度です。関数から取得した値をそのまま使える場合は低い形にしています。
インジケータタイプ
トレンド系
オシレータ系
その他
※ サンプルEAの現状(2022/08/30現在)
小ネタ・その他処理
項目名 | 難易度 | 内容 | |
---|---|---|---|
マーチンゲール法 | 参考程度に作ってみました! | サンプルへ | |
マーチンゲール法(関数) | 手軽にマーチンゲールを組み込めるよう関数化しました | サンプルへ | |
ナンピン法 | ZigZagのEAをベースにナンピンするEAを作りました | サンプルへ | |
マルチタイムフレーム | ZigZagのEAをベースにマルチタイムフレーム化! | サンプルへ | |
高勝率EA | 高勝率のEAを作ったら驚きの結果に! | サンプルへ | |
新規・変更・決済関数 | エラー/リトライを考慮した新規・変更・決済関数 | サンプルへ | |
時間系の処理 | 時間でエントリー等を制御する系の処理です | サンプルへ | |
トレーリングストップ機能 | RSIのEAにトレーリングストップ機能を追加する方法です | サンプルへ | |
経済指標を考慮する(関数) | 経済指標時にエントリーしないようにする処理です | サンプルへ | |
EAのマジックナンバーの考え方 | EAでマジックナンバーを使う際のポイントについてです | 詳細へ | |
指定したポジションを自動決済する | ポジション自動決済EA。MT4上にライン表示等も行っています。 | サンプルへ | |
疑似トレード | MT4で疑似的な裁量トレードを行えるようにする機能です | サンプルへ | |
マーチンゲール法(関数) | マーチンゲール法を他のEAに組み込みたい場合はどうぞ! | サンプルへ | |
証拠金維持率からロット数を調整(関数) | 証拠金維持率から取引ロット数を決める処理です | サンプルへ | |
許容損失額からロット数を計算(関数) | 許容できる損失額からロット数を計算する処理です | サンプルへ | |
夏時間・冬時間の判断(関数) | 夏時間・冬時間の判断する処理です | サンプルへ | |
だれでもEAが作れちゃう? | ChatGPTを使ってEAを作れるか確認しました | 詳細へ | |
EAのソースを整理する方法 | mqhファイルの扱い方について解説しています | 詳細へ | |
移動平均線の上下判定 | 移動平均線の上向き、下向きを判定する方法について記載しています | 詳細へ | |
取引履歴をファイルに書き出す | MT4の取引履歴をファイルに書き出す方法について記載しています | サンプルへ |
※私のサンプルソースがうまく動かない場合はこちらも参考にしてください
※ オススメ記事(EAが使える国内FX業者の一覧)
コメント
はじめまして、ハルともうします。
勉強してもどうしても分かりませんでした。
エントリー条件を満たす度にエントリーするにはどのようなプログラムを書けばいいですか?
例えば、5の移動平均線と10の移動平均線がゴールデンクロスで買いエントリーするとします。
その場合、最初のエントリーはできるのですが、2回目の5と10のゴールデンクロスで買いたいわけですが、そのプログラムが分かりません。
分かる人どうか教えてください。
例)上記のエントリーで合計4回までポジションを持つとして、200と300の移動平均線がデッドクロスの時、持っているポジションをすべて決済するなど。
//マジックナンバー
#define MAGIC 20210204
//パラメーター
extern int FastMA_Period = 5;
extern int SlowMA_Period = 10;
extern double Lots = 0.1;
extern int Slippage = 3;
extern int SLpips = 30; //ストップロスpips幅
//ポジションを決済する
void ClosePositions()
{
for(int i=0; i1 || IsTradeAllowed()==false) return(0);
//移動平均の計算
double FastMA1 = iMA(NULL,0,FastMA_Period,0,
MODE_SMA,PRICE_CLOSE,1);
double SlowMA1 = iMA(NULL,0,SlowMA_Period,0,
MODE_SMA,PRICE_CLOSE,1);
double FastMA2 = iMA(NULL,0,FastMA_Period,0,
MODE_SMA,PRICE_CLOSE,2);
double SlowMA2 = iMA(NULL,0,SlowMA_Period,0,
MODE_SMA,PRICE_CLOSE,2);
//買いシグナル
if(FastMA2 SlowMA1)
{
ClosePositions();
OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,
Ask-SLpips*Point,0,””,MAGIC,0,Blue);
return(0);
}
//売りシグナル
if(FastMA2 >= SlowMA2 && FastMA1 < SlowMA1)
{
ClosePositions();
OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,
Bid-SLpips*Point,0,"",MAGIC,0,Red);
return(0);
}
return(0);
}
こんな感じでどうでしょうか
クロワッサン さん
回答本当にありがとうございます!
こちらも参考にさせていただきますね。
私の方ではなんとか諦めずに頑張ってみますね
クロワッサンさん、コメント有難うございます。
こんな書き方もあるんですね。
すごく参考になります。
はじめましてハルさん、りょうです。
ご質問の「エントリー条件を満たす度にエントリーするにはどのようなプログラムを書けばいいですか?」について回答します。
移動平均線で例を挙げて頂いているので分かりやすいよう、このサイト内の移動平均線のサンプルソース(https://fx-prog.com/ea-ma/)を見て頂きたいです。
そして、ソースの82行目あたりの
『if(total ==0 && orderPtn > 0)』となっている箇所を
『if(total < 4 && orderPtn > 0)』に書き変えてください。こうすることで、ポジションは4つまで持つEAになります。
ストラテジーテスターで動きを確認する際、より例に近づけるためにEAの設定(エキスパート設定)で
①テスト設定タブで『ポジション:Long only』
※ショート判定がわからなかったので、とりあえずロングオンリーにしてます
②パラメータの入力タブで『FasterMA:5 MediumMA:10 SL_GOSA:200』
にして頂くと、例で挙げて頂いた動きにぐっと近づきます。
※唯一、決済の部分だけ指値・逆指値での決済なので、「200と300の移動平均線がデッドクロスの時に一括決済」は上記の内容ではできませんが、決済についても知りたい場合、再度ご質問頂ければ改めて回答しますよ
りょうさん 返信ありがとうございました! 本当に助かります。
もう少し詳しく聞いてもよろしいでしょうか?
2つ聞きたい事があるのですが
① 先日の移動平均の話で、例えば一回目のエントリーチャンス(5移動平均が下から10移動平均を上抜いた時買いエントリー)ではエントリーせず、2回目からエントリーするなどの プログラムも存在するのでしょうか?(つまり最初のエントリーだけ無視して2回目から 順次エントリーしていく事です) もし分かるのであれば教えて欲しいです。
② 先日の移動平均線の話とは関係なく、 例えばローソク足だけの手法で、合計4ポジション保有するトレードだったとして 単純に一本前のローソク足の高値より今(今動いている)の足の高値の方が高くなった瞬間に買いエントリーするとした場合、
今の足のティックで判断してエントリーしていますから 今の足が完全に形成されるまで(次の足になるまで)一本前の高値を何度も往復すれば すぐに4ポジションエントリーしてしまう可能性もあるんですよね?
ですので、一回エントリーした後、10本後のローソク足までエントリーしないなどのプログラム はどのように書けばいいのでしょうか? (連続で近い時間帯で何度もエントリーする事を防ぎたいからです。)
説明が下手で申し訳ありませんが、お時間ある時にでも返信していただけると大変助かります。どうぞよろしくお願いいたします。
ちょっと長く(見づらく)なってしまいましたが回答します。
①は、簡単な方法だとグローバル変数としてエントリータイミング回数を管理するやり方があります。移動平均線のサンプルソースに変更を加えた場合はこんな感じになります。
//+——————————————————————+
//| IMA_TEST.mq4 |
//| Copyright 2020, mef Software. |
//| https://fx-prog.com/ |
//+——————————————————————+
~省略~
double maisuu=0.01;
datetime prevtime;
int entryCnt = 0; //グローバル変数(エントリータイミング回数)
~省略~
int start()
{
int orderPtn=0; //0:何もしない 1:買い 2:売り
int total=0;
double ea_order_stop_price=0,ea_order_good_price=0; //ストップロスレート,利確レート,エントリーレート
bool OrderKekka;
~省略~
//***決済判断箇所***//
total=OrdersTotal();
if(total == 0){
entryCnt = 0; //ポジションが全決済されている場合はエントリータイミング回数を初期化する
}
if(total < 4 && orderPtn > 0)
{
if(orderPtn == 1)
{
ea_order_stop_price = MediumMA_ATAI_1 – SL_GOSA * Point;
ea_order_good_price = Ask + ((Ask – ea_order_stop_price) * 1000 * Point);
}
else if(orderPtn == 2)
{
ea_order_stop_price = MediumMA_ATAI_1 + SL_GOSA * Point;
ea_order_good_price = Bid – ((ea_order_stop_price – Bid) * 1000 * Point);
}
//新規注文(1回目のエントリータイミングはスルーする)
if(entryFlg > 0){
OrderKekka = funcOrder_Send(orderPtn – 1,ea_order_stop_price,ea_order_good_price,0,0);
}
entryCnt = entryCnt + 1; //エントリータイミングカウントアップ
}
return(0);
}
~省略~
このやり方の欠点としてはEAを一度終了させる(MT4を終了する)と、エントリーチャンスはまた1回目からになるという点です。確実な方法としては、現在のチャートから過去にさかのぼってエントリーチャンスがあったのかどうかを確認する方法になりますが、このやり方はFor文で過去のバーを見ていく必要があるのでちょっと複雑になってきます。
②は、サイト内の(https://fx-prog.com/ea-sorce2/)の『エントリー後、バーが10本分を超え&損失中で決済する』に該当しそうです。こちらは、最新ポジションの時間を取得して現在時刻と比較してバーが10本分を超えていたら決済するという内容になります。(決済の箇所をエントリーに変えると行けそうです)
if(OrderSelect(0,SELECT_BY_POS,MODE_TRADES)==true){
//オーダー後、バーが10本を超えた場合エントリーする
if(OrderOpenTime() < iTime(NULL, 0, 10)){ OrderKekka = funcOrder_Send(orderPtn - 1,ea_order_stop_price,ea_order_good_price,0,0); } }
りょうさん
早速の返信ありがとうございました!
自分で教えてもらった事を追加して、ちょっとやってみます!
また分からない事ありましたらよろしくお願いいたします。
本当に助かります。
りょうさん
分からない事がありましたので質問させてください
。
お時間ある時返信していただけると幸いです。
りょうさんのRSIのサンプルコードを見させていただいたのですが、
① int orderPtn=0; //0:何もしない 1:買い 2:売り
というのはorderPtnとは何かの関数なのでしょうか?
どのような効果があるものなのでしょうか?
② //新しい足ができた時だけやる
if(Time[0] != prevtime){
prevtime = Time[0];
}else{
return(0);
}
これの意味は「今動いている足が確定したらエントリーする」という意味でしょうか?その次に
double RSI_atai = iRSI(NULL, 0, RSI_KIKAN, PRICE_CLOSE, 0);
//RSIの値を取得
と書かれていますので、これは現在の値を取っているんですよね?
新しい足が確定したらエントリーするのだったら
iRSI(NULL, 0, RSI_KIKAN, PRICE_CLOSE, 0);
の、最後の0は1にしないといけないのではないのですか?
prevtimeとはどのような意味なのでしょうか?
読んでいて、つまずいてしまい先に考えが進まなくなってしまい、たくさん質問してしまいました。すいません。
ハルさん
色々見て頂いて有難うございます。回答します。
①orderPtnは関数とかではなく、ただの変数です。
私のサンプルソースはどれも、このorderPtn変数でロングエントリーするのかショートエントリーするのか何もしないのかを管理しています。
ロングエントリーの条件に合致した場合はorderPtnに1をセットし、ショートエントリーの条件に合致した場合はorderPtnに2をセットし、どちらの条件にも合致しなかった場合はorderPtnに0をセットしています。
そして、以下の文のようにソースコードの終盤でorderPtnの値をチェックしてエントリーのジャッジをしています。
if(total ==0 && orderPtn > 0)
{
if(orderPtn == 1)
{
ea_order_stop_price = Ask – SL * Point;
ea_order_good_price = Ask + TP * Point;
}
else if(orderPtn == 2)
{
ea_order_stop_price = Bid + SL * Point;
ea_order_good_price = Bid – TP * Point;
}
//新規注文
OrderKekka = funcOrder_Send(orderPtn – 1,ea_order_stop_price,ea_order_good_price,0,0);
}
メリットとしては、コードの可視化であったりロングとショートを逆にすることが簡単にできたりします。
②「今動いている足が確定したらエントリーする」という意味でおおかた問題ありません。
厳密に言えば、「今動いている足が確定したらエントリーするかどうかを判定する」です。
Time[0]というのは新しい足ができた時の時間がセットされています。
簡単に15分足とかでイメージしてもらうと 2021/04/01 18:15:00.000のような感じです。
2021/04/01 18:30:00.000になるまでこの値は変わりません。
prevtimeは変数で、Time[0]の値を常にセットしています。よって、2021/04/01 18:18:40.000の場合、
Time[0]=2021/04/01/ 18:15:00.000
prevtime=2021/04/01/ 18:15:00.000
で同じなのでreturn(0);となり、以降処理はしないのでエントリーしませんしエントリーするかどうかの判断もしていません。
2021/04/01 18:30:00.000になったジャストタイミングでは、
Time[0]=2021/04/01/ 18:30:00.000
prevtime=2021/04/01/ 18:15:00.000
で違うので、prevtimeに2021/04/01/ 18:30:00.000をセットし、
return(0);とはならないのでエントリーするかどうかの判断をしたりエントリーする場合はエントリーするといった形になります。
あと、double RSI_atai = iRSI(NULL, 0, RSI_KIKAN, PRICE_CLOSE, 0);の最後はご指摘通り1が正しいです。
りょうさん
返信本当にありがとうございます。
詳しく説明してくださり助かります。今までで一番わかり易いサイトです。私も挫折せず続けていく事ができます。
りょうさん
お世話になっております。お時間ある時返信していただけると助かります。
RSIの方で書いたのですが、どうしても動かずコンパイルエラーになってしまいます。
どこが悪いのでしょうか?
手法としてはRSIの30以下で買いエントリーしストップとリミットを置きつつ
ストップとリミットに引っかからなくても70以上になったら決済する。
総ポジション数はエントリーチャンスがきたら一回づつエントリーし、4ポジション持つ というものです。(売りはこの逆)
#property copyright “”
#property link “”
#property version “1.00”
#property strict
//パラメーター設定//
#define MAGIC 1
extern double Lots = 0.01; //一回の取引数
extern int MaxEntry = 4;//総ポジション数
extern int Slip = 2; //許容スリッページ数
extern int TP = 100//利益確定ポイント
extern int ST = 100//損切ポイント
extern int RSIPeriod = 14; //指標となる期間
extern int Long_Point = 30; //買いエントリーポイント
extern int Short_Point = 70;//売りエントリーポイント
extern int Exit_Long_Point = 70;//買いエントリー決済ポイント
extern int Exit_Short_Point = 30;//売りエントリー決済ポイント
extern string Comment = “” ;
//変数の設定//
int Ticket_L = 0;
int Ticket_S = 0;
int Exit_L = 0;
int Exit_S = 0;
//+——————————————————————+
//| Expert initialization function |
//+——————————————————————+
int OnInit()
{
//—
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| Expert deinitialization function |
//+——————————————————————+
void OnDeinit(const int reason)
{
//—
}
//+——————————————————————+
//| Expert tick function |
//+——————————————————————+
void OnTick()
{
//買いエントリー決済ポイント
OrderSelect(Ticket_L,SELECT_BY_TICKET);
if (OrderOpenPrice()+ TP * Point = Bid || (iCustom(NULL,0,”RSI”,RSIPeriod,0,1)>=Exit_Long_Point&& (Ticket_L <= MaxEntry && Ticket_L != -1)))
{
Exit_L = OrderClose(Ticket_L,Lots,Bid,Slip,Red);
if(Exit_L == 1){Ticket_L=0;}
}
//売りエントリー決済ポイント
OrderSelect(Ticket_S,SELECT_BY_TICKET);
if (OrderOpenPrice()- TP * Point = Ask || (iCustom(NULL,0,”RSI”,RSIPeriod,0,1)<= Exit_Short_Point&& (Ticket_S <= MaxEntry && Ticket_S != -1)))
{
Exit_S = OrderClose(Ticket_S,Lots,Ask,Slip,Blue);
if(Exit_S == 1){Ticket_S = 0;}
}
//買いエントリーポイント
if(iCustom(NULL,0,"RSI",RSIPeriod,0,1) <= Long_Point)
&& (Ticket_L <= MaxEntry || Ticket_L != -1)
&& (Ticket_S <= MaxEntry || Ticket_S != -1)
&& (High[1] = Short_Point)
&& (Ticket_L <= MaxEntry || Ticket_L != -1)
&& (Ticket_S = Low[0])
{
Ticket_S = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slip,SP,TP,Comment,MAGIC,0,Blue);
}
}
//+——————————————————————+
//売りエントリーポイント
if(iCustom(NULL,0,”RSI”,RSIPeriod,0,1) >= Short_Point)
&& (Ticket_L <= MaxEntry || Ticket_L != -1)
&& (Ticket_S = Low[0])
{
Ticket_S = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slip,SP,TP,Comment,MAGIC,0,Blue);
}
}
一回で送れませんでした。
すいません、買いエントリーポイントと売りエントリーポイントがコピーミスをしてしまいました。
正しくは以下です。
//買いエントリーポイント
if(iCustom(NULL,0,”RSI”,RSIPeriod,0,1) <= Long_Point)
&& (Ticket_L <= MaxEntry || Ticket_L != -1)
&& (Ticket_S <= MaxEntry || Ticket_S != -1)
&& (High[1] = Short_Point)
&& (Ticket_L <= MaxEntry || Ticket_L != -1)
&& (Ticket_S = Low[0])
{
Ticket_S = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slip,SP,TP,Comment,MAGIC,0,Blue);
}
}
すみません、送る時にコピーペーストして送ると
プログラムが変化してそちらに行ってしまうようです。
どうやら私の書いたソースコードがそのままコピーでは送れないようです。
すいませんでした。残念です。
こんにちは。りょうです。
コメント欄は、HTMLタグの改ざん防止とかで勝手にきれちゃうんですかね。ちょっとコメント欄の機能はまた見直してみようと思います。
とりあえず、お問合せ(https://fx-prog.com/contact/)から、ソースを送っていただければ確認しますよ。
いつもお世話になっております。ハルです。
先ほど問い合わせから送ったのですが届いていますでしょうか?
送信ボタンを押したら固まってしまい、送れたか分からない状況になってしまいました。
確認したんですけど、送られてませんでした。
状況は分かってますのでソースコードだけコピペしてもらって再度送って頂いても問題ないです。
りょうさん
いつもお世話になっております。ハルです。
あれから、RSIの単純な売買で勉強しており、複数エントリーと複数ポジションの一
括決済のやり方は何とか分ったのですが、
RSIの30以下で買い、70以上でそれまで持っていたポジションをすべて決済する。という
ロジックで勉強しております。最大ポジション数は4回までです。
①最大エントリー回数を4回までとしたいのですが、無限にエントリーしてしまいます。
②またOrderSend関数で損切注文と利益確定注文をしたのですが、エントリーしませんでし
た。オーダーセンド関数で損切注文と利益確定注文を出せない証券会社があるのでしょう
か?その場合他の方法で損切注文と利益確定注文を出す方法はありますか?
一応ここまでは辿り着きました。どこをどう直せばいいのでしょうか?できれば私のメールアドレスに直接返信していただけると助かります。
//パラメーター設定//
extern int MAGIC = 1;//マジックナンバー
extern double Lots = 0.01; //一回の取引数
extern int MaxEntry = 4;//総ポジション数
extern int Slip = 20; //許容スリッページ数
extern int TP = 100;//利益確定ポイント
extern int ST = 15;//損切ポイント
extern int RSIPeriod = 5; //指標となる期間
extern int Long_Point = 30; //買いエントリーポイント
extern int Exit_Long_Point = 70;//買いエントリー決済ポイント
extern string Comment = “” ;
//変数の設定//
int Ticket_L = 0;
int Exit_L = 0;
datetime NowTime;
datetime OldTime;
int OnInit()
{
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| Expert deinitialization function |
//+——————————————————————+
void OnDeinit(const int reason)
{
//—
}
//+——————————————————————+
//| Expert tick function |
//+——————————————————————+
void OnTick()
{
double rsi = iRSI(NULL,PERIOD_CURRENT,RSIPeriod,PRICE_CLOSE,1);
double rsi2 = iRSI(NULL,PERIOD_CURRENT,RSIPeriod,PRICE_CLOSE,2);
//買いポジション決済
for(Ticket_L = OrdersTotal()- 1 ; Ticket_L >= 0;Ticket_L– )
{
if((OrderSelect(Ticket_L,SELECT_BY_POS,MODE_TRADES)== true ) &&(rsi > Exit_Long_Point))
{
Exit_L = OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slip,Red);
if(Exit_L == 1){Ticket_L=0;}
}
}
//買いエントリーポイント
NowTime = Time[0];
if(NowTime != OldTime)
{
OldTime = NowTime;
if((rsi2 > Long_Point)&&( rsi < Long_Point)&&(Ticket_L < MaxEntry || Ticket_L == -1))
{
Ticket_L = OrderSend(NULL,OP_BUY,Lots,Ask,0,0,0,NULL,MAGIC,0,Red);
}
}
}
//+——————————————————————+