はじめに
「EAを作りたいけど、どこから始めればいいのか分からない…」
そんな初心者の方向けに、本記事では MT4用のEAベーステンプレート(無料配布) を紹介します。
このテンプレートは、売買ロジックを追記するだけでオリジナルEAが完成する仕様。
記事内では ソースコードの仕組み解説・カスタマイズ例をまとめています。
👉 初めてのEA開発を効率よく学びたい方におすすめです。
📘 ベースEAとは?
今回紹介する 00_BASE.mq4
は、EA作成の土台として活用できるテンプレートです。
特徴は以下の通りです。
- EA作成初心者の方でもカスタマイズできるよう処理を統一
- 新規注文・決済・変更の関数を完備
- TP/SLによるシンプルなリスク管理も可能
- 『EAカスタム可能』のタグが付いている記事は、簡単にカスタマイズ可能
▶ 『EAカスタム可能』記事はこちら
👉 このベースを活用すれば、
「ストキャスティクスEA」「ADX EA」「ボリンジャーバンドEA」など複数のインジケーターを組み合わせたEAを短時間で作成できます。
EAの概要とポイント
- マジックナンバーは考慮外としています(シンプルに!)
- ナンピン・複数ポジションには対応していません(シンプルに!)
- 新しいローソク足が確定した時だけ処理(無駄な計算をしない)
- pips数の桁数は各種通貨に対応
シンプルなつくりにしているので、初心者がEA開発を学ぶベースとしても最適です。
EAソースコード
以下が ベースEAの完全ソースコード です。
//+------------------------------------------------------------------+
//| 00_BASE.mq4 |
//| Copyright © 2020-2025 ぷろぐらむFX |
//| https://fx-prog.com/ |
//|使い方:
//|パラメータ設定と、OnTick内「新規注文判断」「TP/SL判断」「決済注文判断」に
//|当サイトのロジックを埋め込むだけでEA化できます。
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020-2025 ぷろぐらむFX"
#property link "https://fx-prog.com/"
#property version "1.00"
#property strict
input double Lots = 0.01; //ロット
input int TP = 100; //利確(pips)
input int SL = 100; //損切り(pips)
//***【パラメータ設定↓】***//
// ここにパラメータ設定を追加してください
// 例:移動平均線とパラボリックのパラメータ設定を追加
//***【パラメータ設定↑】***//
string Ea_Name = "BASE"; //オーダーコメントに使用
double PipValue; //ブローカー桁数に対応した Point 補正
datetime prevtime; //ローソク足時間保持用
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
//デジットチェック
if (Digits == 3 || Digits == 5){
PipValue = Point * 10; // 例: EURUSD 1.23456 → 1pip = 0.00010
}else{
PipValue = Point; // 例: USDJPY 123.45 → 1pip = 0.01
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
int total = OrdersTotal(); //ポジショントータル数をセット
int ea_order_Type = -1; //0:OP_BUY 1:OP_SELL
double ea_order_stop_price = 0; //ストップロスレート
double ea_order_good_price = 0; //利確レート
//新しい足ができた時だけやる
if(Time[0] != prevtime){
prevtime = Time[0];
}else{
return;
}
//ポジションがない場合はエントリー判定
if(total == 0){
bool openBuy = false; //買い新規注文判断
bool openSell = false; //売り新規注文判断
//***【新規注文判断↓】***//
// ここに条件を追加してください
// 例:サンプル記事のエントリー条件をコピペして使います。
//***【新規注文判断↑】***//
//参照するサンプルEAの買いエントリーフラグをセットしてください
if(false){
openBuy =true;
ea_order_Type = OP_BUY;
//参照するサンプルEAの売りエントリーフラグをセットしてください
}else if(false){
openSell =true;
ea_order_Type = OP_SELL;
}
//***【TP/SL判断↓】***//
// TP/SLを変更したい場合はこの部分を変更してください。
// 例:移動平均線のTP/SLを使いたい場合は書き換え
if(openBuy){
ea_order_stop_price = Ask - SL * PipValue;
ea_order_good_price = Ask + TP * PipValue;
}else if(openSell){
ea_order_stop_price = Bid + SL * PipValue;
ea_order_good_price = Bid - TP * PipValue;
}
//***【TP/SL判断↑】***//
if(ea_order_Type > -1){
funcOrder_Send(ea_order_Type,ea_order_stop_price,ea_order_good_price,Lots,Ea_Name,777,0);
}
//ポジションがある場合は決済判定
}else{
bool closeBuy = false; //買いポジション決済判断
bool closeSell = false; //売りポジション決済判断
//***【決済注文判断↓】***//
// 決済もしたい場合はここに決済条件を追加してください
// 例:サンプル記事の決済条件をコピペして使います。
//***【決済注文判断↑】***//
//参照するサンプルEAの買いポジション決済フラグをセットしてください
if(false){
closeBuy =true;
ea_order_Type = OP_BUY;
//参照するサンプルEAの売りポジション決済フラグをセットしてください
}else if(false){
closeSell =true;
ea_order_Type = OP_SELL;
}
if(ea_order_Type > -1){
funcOrder_CloseAll(ea_order_Type, -1, 0);
}
}
return;
}
//★★★★★★★★★★★★★★★★★★★★ ここから下は共通関数 ★★★★★★★★★★★★★★★★★★★★
//+------------------------------------------------------------------+
//|【関数】新規注文関数
//|
//|【引数】 orderType:売買(0=BUY, 1=SELL)
//|【引数】 sl:損切り価格 tp:利確価格
//|【引数】 lots:取引ロット数
//|【引数】 orderComment:オーダーコメント
//|【引数】 magic:マジックNo
//|【引数】 maxSpreadPips: 許容スプレッド[Point] (0=制限なし)
//|
//|【戻値】true=成功 false=失敗
//+------------------------------------------------------------------+
bool funcOrder_Send(int orderType, double sl, double tp, double lots,
string orderComment, int magic, int maxSpreadPoints){
int ticket = -1;
double price = 0;
color clr = clrNONE;
double spread = 0;
// 最大10回リトライ
for(int retry=0; retry<10; retry++)
{
RefreshRates();
// スプレッド取得(MT4表示と同じポイント単位)
spread = MarketInfo(Symbol(), MODE_SPREAD);
// スプレッドチェック(maxSpreadPoints=0 の場合はスキップ)
if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
Print("スプレッド拡大中(", spread,
"ポイント) → 待機中 (リトライ=", retry+1, ")");
Sleep(2000);
continue;
}
// エントリー価格と色を決定
if(orderType == OP_BUY){
price = Ask;
clr = clrBlue;
}else if(orderType == OP_SELL){
price = Bid;
clr = clrRed;
}
ticket = OrderSend(Symbol(), orderType, lots, price,
20, sl, tp, orderComment, magic, 0, clr);
if(ticket > 0){
Print("新規注文成功! チケットNo=", ticket,
" レート=", price, " Lots=", lots,
" スプレッド=", spread, "ポイント");
return true;
}else{
int err = GetLastError();
Print("新規注文失敗 エラーNo=", err,
" リトライ回数=", retry+1);
Sleep(2000);
}
}
return false;
}
//+------------------------------------------------------------------+
//|【関数】変更注文関数 |
//| |
//|【引数】 ticket: 修正対象のチケットNo |
//|【引数】 sl: 新しい損切り価格 |
//|【引数】 tp: 新しい利確価格 |
//|【引数】 maxSpreadPoints: 許容スプレッド[Point] (0=制限なし) |
//| |
//|【戻値】true=成功 false=失敗 |
//+------------------------------------------------------------------+
bool funcOrder_Modify(int ticket, double sl, double tp, int maxSpreadPoints){
double spread = 0;
bool result = false;
// 注文選択
if(!OrderSelect(ticket, SELECT_BY_TICKET)){
Print("funcOrder_Modify: OrderSelect失敗 ticket=", ticket,
" エラー=", GetLastError());
return false;
}
//通貨が違う場合は変更しない
if(OrderSymbol() != Symbol()){
Print("funcOrder_Modify: シンボル不一致 ", OrderSymbol(), "≠", Symbol());
return false;
}
// 最大10回リトライ
for(int retry=0; retry<10; retry++)
{
RefreshRates();
// スプレッド取得(MT4表示と同じポイント単位)
spread = MarketInfo(Symbol(), MODE_SPREAD);
// スプレッドチェック(maxSpreadPoints=0 の場合はスキップ)
if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
Print("スプレッド拡大中(", spread,
"ポイント) → 修正待機中 (リトライ=", retry+1, ")");
Sleep(2000);
continue;
}
// 注文修正
result = OrderModify(ticket,
OrderOpenPrice(), // 価格は変更しない
sl, // 新しい損切り
tp, // 新しい利確
0, // 有効期限(変更しない)
clrNONE);
if(result){
Print("変更注文成功! チケットNo=", ticket,
" 新SL=", sl, " 新TP=", tp,
" スプレッド=", spread, "ポイント");
return true;
}else{
int err = GetLastError();
Print("変更注文失敗 ticket=", ticket,
" エラーNo=", err,
" リトライ回数=", retry+1);
Sleep(2000);
}
}
return false;
}
//+------------------------------------------------------------------+
//|【関数】全決済関数 |
//| |
//|【引数】 orderType : -1=すべて 0=BUYのみ 1=SELLのみ |
//|【引数】 magic: 対象マジック番号 (-1=全マジック対象) |
//|【引数】 maxSpreadPoints: 許容スプレッド[Point] (0=制限なし) |
//| |
//|【戻値】true=全成功 false=一部失敗あり |
//+------------------------------------------------------------------+
bool funcOrder_CloseAll(int orderType, int magic, int maxSpreadPoints){
bool allSuccess = true;
int totalOrders = OrdersTotal();
double spread, closePrice, lots;
int type, ticket;
color clr = clrNONE;
for(int i = totalOrders-1; i >= 0; i--)
{
//オーダーセレクト失敗でスキップ
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
// 同一シンボル以外はスキップ
if(OrderSymbol() != Symbol()) continue;
// マジック番号指定がある場合は一致しないものをスキップ
if(magic != -1 && OrderMagicNumber() != magic) continue;
type = OrderType();
ticket = OrderTicket();
lots = OrderLots();
// orderType指定でフィルタ
if(orderType == 0 && type != OP_BUY) continue;
if(orderType == 1 && type != OP_SELL) continue;
// 最大10回リトライ
bool result = false;
for(int retry=0; retry<10; retry++)
{
RefreshRates();
// スプレッド取得
spread = MarketInfo(Symbol(), MODE_SPREAD);
if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
Print("スプレッド拡大中(", spread,
"ポイント) → クローズ待機中 ticket=", ticket,
" リトライ=", retry+1);
Sleep(2000);
continue;
}
// クローズ価格決定
if(type == OP_BUY){
closePrice = Bid;
clr = clrBlue;
}else if(type == OP_SELL){
closePrice = Ask;
clr = clrRed;
}
result = OrderClose(ticket, lots, closePrice, 20, clr);
if(result){
Print("クローズ成功! チケットNo=", ticket,
" ロット=", lots, " クローズ価格=", closePrice,
" スプレッド=", spread, "ポイント");
break;
}else{
int err = GetLastError();
Print("クローズ失敗 ticket=", ticket,
" エラーNo=", err,
" リトライ=", retry+1);
Sleep(2000);
}
}
if(!result) allSuccess = false;
}
return allSuccess;
}
コードのポイント解説
1. デジットチェック(pipsの定義)
//デジットチェック
if (Digits == 3 || Digits == 5){
PipValue = Point * 10; // 例: EURUSD 1.23456 → 1pip = 0.00010
}else{
PipValue = Point; // 例: USDJPY 123.45 → 1pip = 0.01
}
ブローカーによって小数点桁数が異なるため、1pipsの値を調整しています。
👉 この処理により「20pipsで損切り」「30pipsで利確」といった設定が、どのブローカーでも正しく動作します。
2. 新しいローソク足だけ処理する仕組み
//新しい足ができた時だけやる
if(Time[0] != prevtime){
prevtime = Time[0];
}else{
return;
}
👉 新しい足が確定したときだけ処理を実行するので、
「同じロジックが何度も走る」問題を防げます。
3. ロジックを埋め込む場所
ベースのソースコードに、ロジックを埋め込みます。今回は参考として、移動平均線とパラボリックのインジケータを利用したEAの作成例で記載します。
パラメータ設定
パラメータ設定については、以下にセットしてください。どこソースコードにもパラメータ設定欄があるのでその内容を全てコピペしてきます。
//***【パラメータ設定↓】***//
// ここにパラメータ設定を追加してください
// 例:移動平均線とパラボリックのパラメータ設定を追加
//***【パラメータ設定↑】***//
【例】移動平均線とパラボリックのパラメータ設定
//***【パラメータ設定↓】***//
input int FasterMA = 21; //短期移動平均線期間
input int MediumMA = 84; //中期移動平均線期間
input int MAMode = 1; //移動平均線種別 0 = sma, 1 = ema, 2 = smma, 3 = lwma
input int SL_GOSA = 6; //決済時SLライン(pips)
input double PARA_STEP = 0.02; //パラボリックのステップ
input double PARA_UPPER = 0.2; //パラボリックの上限
input int PARA_ENTRY_DOT_COUNT = 4; //エントリードット数(1~任意)
input int PARA_CLOSE_DOT_COUNT = 2; //決済ドット数(1~任意)
//***【パラメータ設定↑】***//
新規注文
新規注文の処理についても同様に、以下にソースコードをコピペします。
//***【新規注文判断↓】***//
// ここに条件を追加してください
// 例:移動平均線とパラボリックのエントリー条件をコピペして使います。
//***【新規注文判断↑】***//
【例】移動平均線とパラボリックの新規注文
//***【新規注文判断↓】***//
bool isBullMovingAve_S = false;
bool isBearMovingAve_S = false;
//----MA短期値取得
double fasterMA_ATAI_1 = iMA(NULL, 0, FasterMA, 0, MAMode, PRICE_CLOSE, 1); //短期移動平均線で1つ前の値を取得
double fasterMA_ATAI_2 = iMA(NULL, 0, FasterMA, 0, MAMode, PRICE_CLOSE, 2); //短期移動平均線で2つ前の値を取得
//----MA中期値取得
double MediumMA_ATAI_1 = iMA(NULL, 0, MediumMA, 0, MAMode, PRICE_CLOSE, 1); //中期移動平均線で1つ前の値を取得
double MediumMA_ATAI_2 = iMA(NULL, 0, MediumMA, 0, MAMode, PRICE_CLOSE, 2); //中期移動平均線で2つ前の値を取得
//MAのゴールデンクロスでロング(短期MAが上を向いている事)
if(fasterMA_ATAI_1 > MediumMA_ATAI_1 && fasterMA_ATAI_2 < MediumMA_ATAI_2 && fasterMA_ATAI_1 > fasterMA_ATAI_2){
isBullMovingAve_S=true;
}
//MAのデッドクロスでショート(短期MAが下を向いている事)
else if(fasterMA_ATAI_1 < MediumMA_ATAI_1 && fasterMA_ATAI_2 > MediumMA_ATAI_2 && fasterMA_ATAI_1 < fasterMA_ATAI_2){
isBearMovingAve_S=true;
}
bool isBullSAR_S = true;
bool isBearSAR_S = true;
//新規注文チェック
for (int i = 0; i < PARA_ENTRY_DOT_COUNT; i++)
{
double sarVal = iSAR(NULL, 0, PARA_STEP, PARA_UPPER, i);
double priceVal = iClose(NULL, 0, i);
if (priceVal <= sarVal) isBullSAR_S = false; // SARより下に行ったら買い否定
if (priceVal >= sarVal) isBearSAR_S = false; // SARより上に行ったら売り否定
}
//***【新規注文判断↑】***//
次にフラグを更新します。
//参照するサンプルEAの買いエントリーフラグをセットしてください
if(false){
openBuy =true;
ea_order_Type = OP_BUY;
//参照するサンプルEAの売りエントリーフラグをセットしてください
}else if(false){
openSell =true;
ea_order_Type = OP_SELL;
}
各インジケータの、シグナルフラグ(買い:isBull●●●_S、売り:isBear●●●_S)をセットします。今回は移動平均線とパラボリックなので以下のように2つにしています。
※例えば移動平均線のみの場合は、if(isBullMovingAve_S){となります。
//参照するサンプルEAの買いエントリーフラグをセットしてください
if(isBullMovingAve_S && isBullSAR_S ){
openBuy =true;
ea_order_Type = OP_BUY;
//参照するサンプルEAの売りエントリーフラグをセットしてください
}else if(isBearMovingAve_S && isBearSAR_S ){
openSell =true;
ea_order_Type = OP_SELL;
}
TP/SL
TP/SLはベースコードで、パラメータ設定で変更できるようになっていますが、変更したい場合は変更可能です。
//***【TP/SL判断↓】***//
// TP/SLを変更したい場合はこの部分を変更してください。
// 例:移動平均線のTP/SLを使いたい場合は書き換え
if(openBuy){
ea_order_stop_price = Ask - SL * PipValue;
ea_order_good_price = Ask + TP * PipValue;
}else if(openSell){
ea_order_stop_price = Bid + SL * PipValue;
ea_order_good_price = Bid - TP * PipValue;
}
//***【TP/SL判断↑】***//
【例】移動平均線のTP/SLを利用
既存のTP/SL処理は消して、丸々差し替えます。
//***【TP/SL判断↓】***//
double risk = 0;
if(openBuy){
//損切り:中期移動平均線付近(設定で変更可)
ea_order_stop_price = MediumMA_ATAI_1 - SL_GOSA * PipValue;
// リスク幅:エントリー価格(Ask) から SL までの距離
risk = MathAbs(Ask - ea_order_stop_price);
// 利確:同じ幅だけ上
ea_order_good_price = Ask + risk;
}else if(openSell){
ea_order_stop_price = MediumMA_ATAI_1 + SL_GOSA * PipValue;
// リスク幅:エントリー価格(Bid) から SL までの距離
risk = MathAbs(ea_order_stop_price - Bid);
ea_order_good_price = Bid - risk;
}
//***【TP/SL判断↑】***//
決済注文
決済注文も、コピペできます。
//***【決済注文判断↓】***//
// 決済もしたい場合はここに決済条件を追加してください
// 例:決済条件は不要の場合追加しない
//***【決済注文判断↑】***//
今回の、移動平均線とパラボリックのEAはTP/SLで管理するため何も入れないままとします。
ロジックを埋め込む場所は以上です。移動平均線のクロスとパラボリックのドットも確認を確認してエントリーするEAの完成です!
4. 共通関数について
ベースEAには、EA開発でよく使う関数がすでに含まれています。
funcOrder_Send()
… 新規注文(リトライ機能つき)funcOrder_Modify()
… 損切り・利確の変更funcOrder_CloseAll()
… 全決済(BUYのみ/SELLのみ/全ポジション対応)
これらを毎回コピペする必要がなく、ロジック開発に集中できます。
▶ EAで使う新規・変更・決済注文関数の解説はこちら
カスタマイズ例
- 移動平均線とパラボリックを組み合わせたい場合
→ ソースコード解説にて解説。 - ADXと平均足を組み合わせたい場合
→こちらの記事で解説👇
▶ ADXと平均足を組み合わせたEAの作り方(近日公開!)
カスタマイズ可能なコードがある記事一覧はこちら👇
⚠️作成後は必ずバックテストやデモ口座でテストしてください!
まとめ
今回紹介した ベースEAソースコード を利用すれば、
「売買ロジックの追加」だけでEAを素早く作成できます。
- 無駄な処理を省いた効率的なフレームワーク
- 新規注文・決済・変更を関数化済み
- 学習用にも応用用にも便利
👉 今後はこのベースEAを活用して「カスタマイズ可能な各種インジケーターEA」を追加していきます。
✅ 他にも多数のEAサンプルを公開中!
今回紹介した内容以外にも、当サイトではさまざまな
FX自動売買EAのサンプルコードを提供しています。
自分に合った戦略のEAを見つけたい方は、ぜひチェックしてみてください。
📊 【2025年最新】FX自動売買EAランキングも公開中!
当サイトの「どのEA(インジ)が実際に勝っているのか?」を知りたい方はこちら👇
PF(プロフィットファクター)や勝率で徹底比較した最新ランキングから、あなたに最適なEA(インジ)を見つけましょう。
EA開発初心者向けに、今後も実践的なMQL4関数を紹介していきます。
気になる機能やロジックがあれば、ぜひ他の記事もあわせてご覧ください!
コメント