<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>朝日奈りさ (自動売買を作ろう！ の投稿者)</title>
	<atom:link href="https://mql-programing.com/archives/author/risa_mql/feed/" rel="self" type="application/rss+xml" />
	<link>https://mql-programing.com/archives/author/risa_mql/</link>
	<description>MQLプログラミング学習サイト</description>
	<lastBuildDate>Wed, 01 Apr 2026 04:29:28 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://mql-programing.com/main29/wp-content/uploads/2021/02/cropped-ブログアイコン-32x32.jpg</url>
	<title>朝日奈りさ (自動売買を作ろう！ の投稿者)</title>
	<link>https://mql-programing.com/archives/author/risa_mql/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>【MQL4】知っておきたいユーティリティ関数6選！Sleep・RefreshRates・IsTradeAllowed・IsConnected・IsTesting・IsOptimizationの使い方</title>
		<link>https://mql-programing.com/archives/13065/%e3%80%90mql4%e3%80%91%e7%9f%a5%e3%81%a3%e3%81%a6%e3%81%8a%e3%81%8d%e3%81%9f%e3%81%84%e3%83%a6%e3%83%bc%e3%83%86%e3%82%a3%e3%83%aa%e3%83%86%e3%82%a3%e9%96%a2%e6%95%b06%e9%81%b8%ef%bc%81sleep%e3%83%bbr/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[ユーティリティ関数]]></category>
		<category><![CDATA[Sleep]]></category>
		<category><![CDATA[バックテスト]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13065</guid>

					<description><![CDATA[<p>EA（自動売買プログラム）を作っていると、「注文を出す前にサーバーと接続できているか確認したい」「バックテスト中は処理を軽くしたい」といった場面に必ず出くわします。こうした場面で活躍するのが、MQL4に用意されたユーティ [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13065/%e3%80%90mql4%e3%80%91%e7%9f%a5%e3%81%a3%e3%81%a6%e3%81%8a%e3%81%8d%e3%81%9f%e3%81%84%e3%83%a6%e3%83%bc%e3%83%86%e3%82%a3%e3%83%aa%e3%83%86%e3%82%a3%e9%96%a2%e6%95%b06%e9%81%b8%ef%bc%81sleep%e3%83%bbr/">【MQL4】知っておきたいユーティリティ関数6選！Sleep・RefreshRates・IsTradeAllowed・IsConnected・IsTesting・IsOptimizationの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>EA（自動売買プログラム）を作っていると、「注文を出す前にサーバーと接続できているか確認したい」「バックテスト中は処理を軽くしたい」といった場面に必ず出くわします。こうした場面で活躍するのが、MQL4に用意された<strong>ユーティリティ関数</strong>たちです。</p>
<p>今回は、EA開発で特に使用頻度が高い以下の<strong>6つのユーティリティ関数</strong>をまとめて解説します。</p>
<ul>
<li><strong>Sleep()</strong> — 処理の一時停止</li>
<li><strong>RefreshRates()</strong> — 価格データの最新化</li>
<li><strong>IsTradeAllowed()</strong> — 自動売買の許可状態を確認</li>
<li><strong>IsConnected()</strong> — サーバー接続の確認</li>
<li><strong>IsTesting()</strong> — バックテスト中かどうかの判定</li>
<li><strong>IsOptimization()</strong> — 最適化モードかどうかの判定</li>
</ul>
<p>それぞれの基本的な使い方から、最後に6つすべてを組み合わせた実践テンプレートまで紹介しますので、ぜひ最後までお読みください。</p>
<h2><span id="toc1">Sleep() — ミリ秒単位で処理を一時停止する</span></h2>
<h3><span id="toc2">基本構文</span></h3>
<pre><code class="language-mql4">void Sleep(int milliseconds);
</code></pre>
<p><strong>Sleep()</strong>は、指定したミリ秒（1000ミリ秒＝1秒）だけEAの処理を一時停止する関数です。注文のリトライ処理やサーバーとの通信待ちなどで頻繁に使われます。</p>
<h3><span id="toc3">使用例：注文失敗時のリトライ</span></h3>
<p>注文送信が失敗した場合、少し間をおいてからリトライするのが一般的なパターンです。</p>
<pre><code class="language-mql4">int ticket = -1;
int retryCount = 3;

for(int i = 0; i < retryCount; i++)
{
    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Buy Order", 0, 0, clrBlue);

    if(ticket > 0)
    {
        Print("注文成功！ チケット番号: ", ticket);
        break;
    }
    else
    {
        int err = GetLastError();
        Print("注文失敗（", i + 1, "回目） エラー: ", err);
        Sleep(1000);  // 1秒待ってからリトライ
    }
}
</code></pre>
<h3><span id="toc4">Sleep()の注意点</span></h3>
<ul>
<li><strong>ストラテジーテスターでは無視されます。</strong>バックテスト中にSleep()を呼んでも、実際には一時停止しません。テスト速度に影響を与えないための仕様です。</li>
<li>Sleep()の内部では<strong>約0.1秒ごと</strong>にEAの停止フラグがチェックされています。そのため、Sleep(10000)（10秒停止）を実行中でも、ユーザーがEAを停止すれば比較的すぐに処理が終了します。</li>
<li>カスタムインジケーターの中では使用できません。EAおよびスクリプト専用の関数です。</li>
</ul>
<h2><span id="toc5">RefreshRates() — 価格データを最新の状態に更新する</span></h2>
<h3><span id="toc6">基本構文</span></h3>
<pre><code class="language-mql4">bool RefreshRates();
</code></pre>
<p><strong>RefreshRates()</strong>は、Bid、Ask、Volumeなどの定義済み変数を最新のサーバーデータに更新する関数です。更新に成功するとtrueを返します。</p>
<h3><span id="toc7">なぜRefreshRates()が必要なのか</span></h3>
<p>EAの<code>OnTick()</code>が呼び出された瞬間に、BidやAskには最新の値がセットされます。しかし、その後にSleep()で待機したり、重い計算処理を行ったりすると、BidやAskの値が古くなってしまう可能性があります。</p>
<p>つまり、<strong>Sleep()の後にはRefreshRates()を呼ぶのが鉄則</strong>です。</p>
<h3><span id="toc8">使用例：Sleep()とRefreshRates()のセット</span></h3>
<pre><code class="language-mql4">// 注文失敗 → 待機 → 価格を更新してリトライ
Sleep(1000);
RefreshRates();  // Bid/Askを最新に更新

// 更新後のAskで再度注文
ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Retry Order", 0, 0, clrBlue);
</code></pre>
<p>RefreshRates()を呼ばずに古いAsk値で注文を出すと、「Off quotes（無効な価格）」エラーが発生する原因になります。注意しましょう。</p>
<h2><span id="toc9">IsTradeAllowed() — 自動売買が許可されているか確認する</span></h2>
<h3><span id="toc10">基本構文</span></h3>
<pre><code class="language-mql4">bool IsTradeAllowed();
</code></pre>
<p><strong>IsTradeAllowed()</strong>は、EAによる自動売買が許可されている場合にtrueを返す関数です。具体的には、以下の2つの条件を確認しています。</p>
<ul>
<li>MetaTraderのツールバーにある<strong>「自動売買」ボタンがON</strong>になっているか</li>
<li>他のEAやスクリプトが取引コンテキストを使用中（ビジー状態）でないか</li>
</ul>
<h3><span id="toc11">使用例：注文前の安全チェック</span></h3>
<pre><code class="language-mql4">void OnTick()
{
    // 自動売買が許可されていなければ何もしない
    if(!IsTradeAllowed())
    {
        Print("自動売買が無効です。ツールバーの自動売買ボタンを確認してください。");
        return;
    }

    // ここから注文ロジック
    // ...
}
</code></pre>
<h3><span id="toc12">取引コンテキストのビジー状態に対処する</span></h3>
<p>同一のMetaTrader上で複数のEAが動作している場合、1つのEAが注文処理を行っている間は他のEAの取引がブロックされます。このような場合は、少し待ってから再確認するのが有効です。</p>
<pre><code class="language-mql4">// 取引コンテキストが空くまで待機（最大5秒）
for(int i = 0; i < 10; i++)
{
    if(IsTradeAllowed())
        break;

    Print("取引コンテキストがビジー状態です。待機中...");
    Sleep(500);
}
</code></pre>
<h2><span id="toc13">IsConnected() — サーバーとの接続状態を確認する</span></h2>
<h3><span id="toc14">基本構文</span></h3>
<pre><code class="language-mql4">bool IsConnected();
</code></pre>
<p><strong>IsConnected()</strong>は、MetaTraderクライアントがブローカーのサーバーと接続されている場合にtrueを返す関数です。</p>
<h3><span id="toc15">使用例：接続チェック</span></h3>
<pre><code class="language-mql4">void OnTick()
{
    if(!IsConnected())
    {
        Print("サーバーに接続されていません！ 注文処理をスキップします。");
        return;
    }

    // 接続確認OK → 通常の処理へ
}
</code></pre>
<h3><span id="toc16">VPS運用時に特に重要</span></h3>
<p>VPS（仮想専用サーバー）でEAを24時間稼働させている場合、ネットワークの一時的な切断は避けられません。IsConnected()で接続状態をチェックし、切断時にはアラートを出すなどの処理を組み込んでおくと安心です。</p>
<pre><code class="language-mql4">static datetime lastAlertTime = 0;

if(!IsConnected())
{
    // 5分に1回だけアラート
    if(TimeCurrent() - lastAlertTime > 300)
    {
        Alert("サーバー接続が切断されています！");
        lastAlertTime = TimeCurrent();
    }
    return;
}
</code></pre>
<h2><span id="toc17">IsTesting() — バックテスト中かどうかを判定する</span></h2>
<h3><span id="toc18">基本構文</span></h3>
<pre><code class="language-mql4">bool IsTesting();
</code></pre>
<p><strong>IsTesting()</strong>は、EAがストラテジーテスター上で動作しているときにtrueを返す関数です。ライブ口座やデモ口座で動かしている場合はfalseになります。</p>
<h3><span id="toc19">使用例：テスト時にGUI処理をスキップして高速化</span></h3>
<p>バックテスト（特にビジュアルモードではない通常テスト）では、画面への描画処理は不要です。Comment()やObjectCreate()といった描画関数をスキップすることで、テスト速度を大幅に向上できます。</p>
<pre><code class="language-mql4">// グローバル変数としてフラグを用意
bool gIsTesting = false;

int OnInit()
{
    // init()内で1度だけ判定すれば十分
    gIsTesting = IsTesting();
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    // テスト中でなければ画面に情報を表示
    if(!gIsTesting)
    {
        Comment("Bid: ", Bid, "  Ask: ", Ask, "  Spread: ", MarketInfo(Symbol(), MODE_SPREAD));
    }

    // 売買ロジック...
}
</code></pre>
<p><strong>ポイント：</strong>IsTesting()の戻り値はEAの実行中に変わることはありません。そのため、<code>OnInit()</code>内で一度だけ判定してグローバル変数に保存すれば十分です。OnTick()のたびに呼び出す必要はなく、わずかですがパフォーマンスの改善につながります。</p>
<h2><span id="toc20">IsOptimization() — 最適化モードかどうかを判定する</span></h2>
<h3><span id="toc21">基本構文</span></h3>
<pre><code class="language-mql4">bool IsOptimization();
</code></pre>
<p><strong>IsOptimization()</strong>は、ストラテジーテスターの最適化モードで実行されているときにtrueを返す関数です。最適化モードでは、パラメータの組み合わせを大量にテストするため、不要な処理を極力省くことが重要になります。</p>
<h3><span id="toc22">使用例：最適化中はPrint()を抑制する</span></h3>
<p>最適化モードでは、<strong>Print()による出力がログに記録されません</strong>。つまり、Print()を呼んでもデバッグの役に立たないだけでなく、処理のオーバーヘッドだけが残ります。</p>
<pre><code class="language-mql4">bool gIsOptimization = false;

int OnInit()
{
    gIsOptimization = IsOptimization();
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    // 最適化中はデバッグ出力をスキップ
    if(!gIsOptimization)
    {
        Print("現在のBid: ", Bid, " Ask: ", Ask);
    }

    // 売買ロジック...
}
</code></pre>
<h3><span id="toc23">IsTesting()との使い分け</span></h3>
<p>IsTesting()とIsOptimization()の関係を整理しておきましょう。</p>
<table>
<thead>
<tr>
<th>状態</th>
<th>IsTesting()</th>
<th>IsOptimization()</th>
</tr>
</thead>
<tbody>
<tr>
<td>ライブ口座 / デモ口座</td>
<td>false</td>
<td>false</td>
</tr>
<tr>
<td>バックテスト（通常）</td>
<td>true</td>
<td>false</td>
</tr>
<tr>
<td>バックテスト（ビジュアルモード）</td>
<td>true</td>
<td>false</td>
</tr>
<tr>
<td>最適化モード</td>
<td>true</td>
<td>true</td>
</tr>
</tbody>
</table>
<p>最適化モードのときはIsTesting()もtrueになります。つまり「IsTesting()がtrueかつIsOptimization()がfalse」であれば通常のバックテスト、「両方ともtrue」であれば最適化中ということになります。</p>
<h2><span id="toc24">実践テンプレート：6つの関数を組み合わせた安全な注文処理</span></h2>
<p>ここまで紹介した6つの関数をすべて組み合わせた、実践的な注文処理テンプレートを紹介します。実際のEA開発でそのまま活用できる構成です。</p>
<pre><code class="language-mql4">//--- グローバル変数
bool gIsTesting      = false;
bool gIsOptimization = false;

//+------------------------------------------------------------------+
//| 初期化関数                                                         |
//+------------------------------------------------------------------+
int OnInit()
{
    // 実行環境フラグを初期化時に1度だけ判定
    gIsTesting      = IsTesting();
    gIsOptimization = IsOptimization();

    if(!gIsOptimization)
        Print("EA初期化完了 テストモード: ", gIsTesting);

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 安全な買い注文関数                                                  |
//+------------------------------------------------------------------+
int SafeBuyOrder(double lots, int slippage, double sl, double tp, string comment)
{
    int maxRetry = 3;
    int ticket   = -1;

    //--- 1. サーバー接続チェック（テスト時はスキップ）
    if(!gIsTesting &amp;&amp; !IsConnected())
    {
        Print("エラー: サーバーに接続されていません");
        return(-1);
    }

    //--- 2. 自動売買許可チェック
    if(!IsTradeAllowed())
    {
        Print("エラー: 自動売買が許可されていません");
        return(-1);
    }

    //--- 3. リトライループ
    for(int i = 0; i < maxRetry; i++)
    {
        // 価格データを最新に更新
        RefreshRates();

        // 注文送信
        ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, slippage, sl, tp, comment, 0, 0, clrBlue);

        if(ticket > 0)
        {
            if(!gIsOptimization)
                Print("買い注文成功！ チケット: ", ticket, " 価格: ", Ask);
            break;
        }
        else
        {
            int err = GetLastError();
            if(!gIsOptimization)
                Print("買い注文失敗（", i + 1, "/", maxRetry, "） エラーコード: ", err);

            // 最後のリトライでなければ待機
            if(i < maxRetry - 1)
            {
                Sleep(1000);  // 1秒待機（テスターでは無視される）
            }
        }
    }

    return(ticket);
}

//+------------------------------------------------------------------+
//| ティックごとの処理                                                  |
//+------------------------------------------------------------------+
void OnTick()
{
    //--- 画面表示（通常バックテスト・最適化時はスキップ）
    if(!gIsTesting)
    {
        Comment("EA稼働中 | Bid: ", Bid, " | Ask: ", Ask,
                " | 接続: ", (IsConnected() ? "OK" : "NG"),
                " | 自動売買: ", (IsTradeAllowed() ? "許可" : "不可"));
    }

    //--- ここに売買条件を記述 ---
    // 例: 買い条件を満たしたら注文
    // int ticket = SafeBuyOrder(0.1, 3, 0, 0, "Sample EA");
}

//+------------------------------------------------------------------+
//| 終了処理                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    if(!gIsOptimization)
        Print("EA停止 理由コード: ", reason);

    // テスト時でなければコメントをクリア
    if(!gIsTesting)
        Comment("");
}
</code></pre>
<p>このテンプレートでは、以下のポイントを押さえています。</p>
<ul>
<li><strong>OnInit()で環境フラグを一度だけ判定</strong> — IsTesting()やIsOptimization()を毎ティック呼ぶ無駄を排除</li>
<li><strong>注文前にIsConnected()とIsTradeAllowed()をチェック</strong> — 接続切れや自動売買無効時のエラーを未然に防止</li>
<li><strong>リトライ時にSleep() + RefreshRates()をセットで使用</strong> — 待機後に最新価格を取得してから再注文</li>
<li><strong>最適化中はPrint()をスキップ</strong> — 不要な処理のオーバーヘッドを削減</li>
<li><strong>テスト中はComment()による画面描画をスキップ</strong> — バックテストの高速化</li>
</ul>
<h2><span id="toc25">まとめ</span></h2>
<p>今回紹介した6つのユーティリティ関数を一覧表で振り返りましょう。</p>
<table>
<thead>
<tr>
<th>関数名</th>
<th>用途</th>
<th>主な使いどころ</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sleep()</td>
<td>処理の一時停止</td>
<td>注文リトライ時の待機</td>
</tr>
<tr>
<td>RefreshRates()</td>
<td>価格データの更新</td>
<td>Sleep()の後、重い計算の後</td>
</tr>
<tr>
<td>IsTradeAllowed()</td>
<td>自動売買許可の確認</td>
<td>注文送信前のチェック</td>
</tr>
<tr>
<td>IsConnected()</td>
<td>サーバー接続の確認</td>
<td>注文送信前、VPS運用時</td>
</tr>
<tr>
<td>IsTesting()</td>
<td>バックテスト判定</td>
<td>GUI処理のスキップ</td>
</tr>
<tr>
<td>IsOptimization()</td>
<td>最適化モード判定</td>
<td>Print()の抑制</td>
</tr>
</tbody>
</table>
<p>これらの関数は単体で使うだけでなく、<strong>組み合わせて使うことで真価を発揮</strong>します。特に「Sleep() → RefreshRates()」のセットや、「IsTesting() / IsOptimization()による処理の出し分け」は、EA開発における定番テクニックです。</p>
<p>今回紹介した実践テンプレートをベースに、ご自身のEAに安全で効率的な処理を組み込んでみてください。堅牢なEAを作る第一歩になるはずです。</p>
<p>投稿 <a href="https://mql-programing.com/archives/13065/%e3%80%90mql4%e3%80%91%e7%9f%a5%e3%81%a3%e3%81%a6%e3%81%8a%e3%81%8d%e3%81%9f%e3%81%84%e3%83%a6%e3%83%bc%e3%83%86%e3%82%a3%e3%83%aa%e3%83%86%e3%82%a3%e9%96%a2%e6%95%b06%e9%81%b8%ef%bc%81sleep%e3%83%bbr/">【MQL4】知っておきたいユーティリティ関数6選！Sleep・RefreshRates・IsTradeAllowed・IsConnected・IsTesting・IsOptimizationの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】市場情報を取得する関数を完全解説！MarketInfo・SymbolInfoDouble・SymbolInfoInteger・SymbolInfoStringの使い方</title>
		<link>https://mql-programing.com/archives/13062/%e3%80%90mql4%e3%80%91%e5%b8%82%e5%a0%b4%e6%83%85%e5%a0%b1%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%aa%ac%ef%bc%81marketinfo%e3%83%bbsymbol/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Wed, 22 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[MarketInfo]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[SymbolInfoDouble]]></category>
		<category><![CDATA[市場情報関数]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13062</guid>

					<description><![CDATA[<p>EA（自動売買）を開発するとき、「現在のスプレッドはいくつ？」「このブローカーのストップレベルは？」「1pipあたりの価値は？」といった市場情報の取得は欠かせません。MQL4には、これらの情報を取得するための関数がいくつ [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13062/%e3%80%90mql4%e3%80%91%e5%b8%82%e5%a0%b4%e6%83%85%e5%a0%b1%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%aa%ac%ef%bc%81marketinfo%e3%83%bbsymbol/">【MQL4】市場情報を取得する関数を完全解説！MarketInfo・SymbolInfoDouble・SymbolInfoInteger・SymbolInfoStringの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>EA（自動売買）を開発するとき、「現在のスプレッドはいくつ？」「このブローカーのストップレベルは？」「1pipあたりの価値は？」といった市場情報の取得は欠かせません。MQL4には、これらの情報を取得するための関数がいくつか用意されています。</p>
<p>この記事では、<strong>MarketInfo関数</strong>と、より新しい<strong>SymbolInfoDouble・SymbolInfoInteger・SymbolInfoString関数</strong>の使い方を、実践的なコード例とともに徹底解説します。</p>
<h2><span id="toc1">MarketInfo関数 ― MQL4の基本</span></h2>
<p>MarketInfo関数は、気配値表示ウィンドウに表示されている通貨ペアのマーケット情報を取得するための、MQL4で最も古くから使われている関数です。</p>
<h3><span id="toc2">基本構文</span></h3>
<pre><code class="language-mql4">double MarketInfo(string symbol, int type);
</code></pre>
<p>第1引数に通貨ペア名（例：&#8221;USDJPY&#8221;）、第2引数にMODE定数を指定します。戻り値はすべてdouble型です。</p>
<h3><span id="toc3">主なMODE定数一覧</span></h3>
<table>
<thead>
<tr>
<th>MODE定数</th>
<th>値</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>MODE_BID</td>
<td>9</td>
<td>現在のBid価格</td>
</tr>
<tr>
<td>MODE_ASK</td>
<td>10</td>
<td>現在のAsk価格</td>
</tr>
<tr>
<td>MODE_POINT</td>
<td>11</td>
<td>1ポイントの値（例：0.00001）</td>
</tr>
<tr>
<td>MODE_DIGITS</td>
<td>12</td>
<td>小数点以下の桁数</td>
</tr>
<tr>
<td>MODE_SPREAD</td>
<td>13</td>
<td>スプレッド（ポイント単位）</td>
</tr>
<tr>
<td>MODE_STOPLEVEL</td>
<td>14</td>
<td>ストップレベル（ポイント単位）</td>
</tr>
<tr>
<td>MODE_LOTSIZE</td>
<td>15</td>
<td>1ロットあたりの契約サイズ</td>
</tr>
<tr>
<td>MODE_TICKVALUE</td>
<td>16</td>
<td>1ティックあたりの価値（口座通貨建て）</td>
</tr>
<tr>
<td>MODE_TICKSIZE</td>
<td>17</td>
<td>1ティックのサイズ</td>
</tr>
<tr>
<td>MODE_SWAPLONG</td>
<td>18</td>
<td>ロングポジションのスワップ</td>
</tr>
<tr>
<td>MODE_SWAPSHORT</td>
<td>19</td>
<td>ショートポジションのスワップ</td>
</tr>
<tr>
<td>MODE_MINLOT</td>
<td>24</td>
<td>最小ロット数</td>
</tr>
<tr>
<td>MODE_LOTSTEP</td>
<td>25</td>
<td>ロットのステップ</td>
</tr>
<tr>
<td>MODE_MAXLOT</td>
<td>26</td>
<td>最大ロット数</td>
</tr>
<tr>
<td>MODE_MARGININIT</td>
<td>28</td>
<td>初期証拠金</td>
</tr>
<tr>
<td>MODE_MARGINREQUIRED</td>
<td>31</td>
<td>1ロットあたりの必要証拠金</td>
</tr>
<tr>
<td>MODE_FREEZELEVEL</td>
<td>33</td>
<td>フリーズレベル（ポイント単位）</td>
</tr>
</tbody>
</table>
<h3><span id="toc4">基本的な使用例</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    string sym = Symbol(); // 現在のチャートの通貨ペア

    double bid       = MarketInfo(sym, MODE_BID);
    double ask       = MarketInfo(sym, MODE_ASK);
    double spread    = MarketInfo(sym, MODE_SPREAD);
    double stopLevel = MarketInfo(sym, MODE_STOPLEVEL);
    double tickValue = MarketInfo(sym, MODE_TICKVALUE);
    double minLot    = MarketInfo(sym, MODE_MINLOT);

    PrintFormat("Bid=%.5f  Ask=%.5f  Spread=%.0f  StopLevel=%.0f",
                bid, ask, spread, stopLevel);
    PrintFormat("TickValue=%.5f  MinLot=%.2f", tickValue, minLot);
}
</code></pre>
<p>MarketInfo関数はシンプルで使いやすいですが、戻り値がすべてdouble型のため、本来は整数値であるスプレッドや桁数もdoubleで返ってきます。キャストが必要になる場面がある点は覚えておきましょう。</p>
<h2><span id="toc5">SymbolInfo系関数 ― より型安全な新しい方法</span></h2>
<p>MQL4のビルド600以降では、MarketInfoの代替として<strong>SymbolInfo系関数</strong>が使えるようになりました。これらはMQL5と共通の関数であり、将来的なMQL5移行を見据えるなら、こちらを使うのがおすすめです。</p>
<p>SymbolInfo系関数は、取得するデータの型に応じて3つに分かれています。</p>
<table>
<thead>
<tr>
<th>関数名</th>
<th>戻り値の型</th>
<th>主な用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>SymbolInfoDouble</td>
<td>double</td>
<td>価格、スワップ、ロット情報など</td>
</tr>
<tr>
<td>SymbolInfoInteger</td>
<td>long（整数）</td>
<td>スプレッド、桁数、ストップレベルなど</td>
</tr>
<tr>
<td>SymbolInfoString</td>
<td>string</td>
<td>通貨名、シンボル説明など</td>
</tr>
</tbody>
</table>
<h2><span id="toc6">SymbolInfoDouble ― double型の市場情報を取得</span></h2>
<p>SymbolInfoDoubleには2つの書式があります。</p>
<h3><span id="toc7">書式1：戻り値で直接受け取る</span></h3>
<pre><code class="language-mql4">double SymbolInfoDouble(string symbol, ENUM_SYMBOL_INFO_DOUBLE prop_id);
</code></pre>
<h3><span id="toc8">書式2：参照引数で受け取る（成否判定付き）</span></h3>
<pre><code class="language-mql4">bool SymbolInfoDouble(string symbol, ENUM_SYMBOL_INFO_DOUBLE prop_id, double &amp;value);
</code></pre>
<p>書式2はboolを返すため、取得が成功したかどうかを判定できます。安全なコードを書きたい場合はこちらを推奨します。</p>
<h3><span id="toc9">主なプロパティID</span></h3>
<table>
<thead>
<tr>
<th>プロパティID</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SYMBOL_BID</td>
<td>現在のBid価格</td>
</tr>
<tr>
<td>SYMBOL_ASK</td>
<td>現在のAsk価格</td>
</tr>
<tr>
<td>SYMBOL_POINT</td>
<td>1ポイントの値</td>
</tr>
<tr>
<td>SYMBOL_TRADE_TICK_VALUE</td>
<td>1ティックの価値</td>
</tr>
<tr>
<td>SYMBOL_TRADE_TICK_SIZE</td>
<td>1ティックのサイズ</td>
</tr>
<tr>
<td>SYMBOL_TRADE_CONTRACT_SIZE</td>
<td>契約サイズ</td>
</tr>
<tr>
<td>SYMBOL_VOLUME_MIN</td>
<td>最小ロット</td>
</tr>
<tr>
<td>SYMBOL_VOLUME_MAX</td>
<td>最大ロット</td>
</tr>
<tr>
<td>SYMBOL_VOLUME_STEP</td>
<td>ロットステップ</td>
</tr>
<tr>
<td>SYMBOL_SWAP_LONG</td>
<td>ロングスワップ</td>
</tr>
<tr>
<td>SYMBOL_SWAP_SHORT</td>
<td>ショートスワップ</td>
</tr>
<tr>
<td>SYMBOL_MARGIN_INITIAL</td>
<td>初期証拠金</td>
</tr>
</tbody>
</table>
<h3><span id="toc10">コード例</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    string sym = Symbol();

    // 書式1：直接取得
    double bid = SymbolInfoDouble(sym, SYMBOL_BID);
    double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
    PrintFormat("Bid=%.5f  Ask=%.5f", bid, ask);

    // 書式2：成否判定付き
    double tickValue;
    if(SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE, tickValue))
        PrintFormat("TickValue = %.5f", tickValue);
    else
        Print("TickValue の取得に失敗しました");
}
</code></pre>
<h2><span id="toc11">SymbolInfoInteger ― 整数型の市場情報を取得</span></h2>
<p>スプレッドや桁数など、整数で扱うべき情報を<strong>long型</strong>で返します。MarketInfoではdoubleで返っていたものが正しい型で取得できるようになりました。</p>
<h3><span id="toc12">主なプロパティID</span></h3>
<table>
<thead>
<tr>
<th>プロパティID</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SYMBOL_SPREAD</td>
<td>スプレッド（ポイント単位）</td>
</tr>
<tr>
<td>SYMBOL_DIGITS</td>
<td>小数点以下の桁数</td>
</tr>
<tr>
<td>SYMBOL_TRADE_STOPS_LEVEL</td>
<td>ストップレベル（ポイント単位）</td>
</tr>
<tr>
<td>SYMBOL_TRADE_FREEZE_LEVEL</td>
<td>フリーズレベル（ポイント単位）</td>
</tr>
<tr>
<td>SYMBOL_TRADE_EXEMODE</td>
<td>約定方式</td>
</tr>
<tr>
<td>SYMBOL_TIME</td>
<td>最終ティックの時刻</td>
</tr>
</tbody>
</table>
<pre><code class="language-mql4">void OnStart()
{
    string sym = Symbol();

    long spread    = SymbolInfoInteger(sym, SYMBOL_SPREAD);
    long digits    = SymbolInfoInteger(sym, SYMBOL_DIGITS);
    long stopLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);

    PrintFormat("Spread=%d  Digits=%d  StopLevel=%d",
                (int)spread, (int)digits, (int)stopLevel);
}
</code></pre>
<h2><span id="toc13">SymbolInfoString ― 文字列型の市場情報を取得</span></h2>
<p>通貨ペアの基軸通貨や決済通貨、説明文などの文字列情報を取得します。</p>
<table>
<thead>
<tr>
<th>プロパティID</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SYMBOL_CURRENCY_BASE</td>
<td>基軸通貨（例：&#8221;USD&#8221;）</td>
</tr>
<tr>
<td>SYMBOL_CURRENCY_PROFIT</td>
<td>決済通貨（例：&#8221;JPY&#8221;）</td>
</tr>
<tr>
<td>SYMBOL_CURRENCY_MARGIN</td>
<td>証拠金通貨</td>
</tr>
<tr>
<td>SYMBOL_DESCRIPTION</td>
<td>シンボルの説明文</td>
</tr>
<tr>
<td>SYMBOL_PATH</td>
<td>シンボルツリー内のパス</td>
</tr>
</tbody>
</table>
<pre><code class="language-mql4">void OnStart()
{
    string sym = Symbol();

    string baseCurrency   = SymbolInfoString(sym, SYMBOL_CURRENCY_BASE);
    string profitCurrency = SymbolInfoString(sym, SYMBOL_CURRENCY_PROFIT);
    string description    = SymbolInfoString(sym, SYMBOL_DESCRIPTION);

    PrintFormat("基軸通貨=%s  決済通貨=%s", baseCurrency, profitCurrency);
    PrintFormat("説明: %s", description);
}
</code></pre>
<h2><span id="toc14">MarketInfo と SymbolInfo系の対応関係</span></h2>
<p>既存のコードをSymbolInfo系に書き換えたいときは、以下の対応表を参考にしてください。</p>
<table>
<thead>
<tr>
<th>MarketInfo (MODE定数)</th>
<th>SymbolInfo系 (プロパティID)</th>
<th>関数</th>
</tr>
</thead>
<tbody>
<tr>
<td>MODE_BID</td>
<td>SYMBOL_BID</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_ASK</td>
<td>SYMBOL_ASK</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_POINT</td>
<td>SYMBOL_POINT</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_DIGITS</td>
<td>SYMBOL_DIGITS</td>
<td>SymbolInfoInteger</td>
</tr>
<tr>
<td>MODE_SPREAD</td>
<td>SYMBOL_SPREAD</td>
<td>SymbolInfoInteger</td>
</tr>
<tr>
<td>MODE_STOPLEVEL</td>
<td>SYMBOL_TRADE_STOPS_LEVEL</td>
<td>SymbolInfoInteger</td>
</tr>
<tr>
<td>MODE_TICKVALUE</td>
<td>SYMBOL_TRADE_TICK_VALUE</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_MINLOT</td>
<td>SYMBOL_VOLUME_MIN</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_LOTSTEP</td>
<td>SYMBOL_VOLUME_STEP</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_MAXLOT</td>
<td>SYMBOL_VOLUME_MAX</td>
<td>SymbolInfoDouble</td>
</tr>
<tr>
<td>MODE_FREEZELEVEL</td>
<td>SYMBOL_TRADE_FREEZE_LEVEL</td>
<td>SymbolInfoInteger</td>
</tr>
</tbody>
</table>
<h2><span id="toc15">実践テクニック</span></h2>
<h3><span id="toc16">①スプレッドフィルター</span></h3>
<p>スプレッドが広がっているときにエントリーを避ける、シンプルなフィルターです。</p>
<pre><code class="language-mql4">// スプレッドが指定pips以上なら取引しない
bool IsSpreadOK(int maxSpreadPoints)
{
    long spread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD);
    if(spread > maxSpreadPoints)
    {
        PrintFormat("スプレッドが広すぎます: %d > %d", (int)spread, maxSpreadPoints);
        return false;
    }
    return true;
}
</code></pre>
<h3><span id="toc17">②ストップレベルを考慮したSL/TP設定</span></h3>
<p>ブローカーによってはストップレベルが設定されており、現在価格から一定以上離れていないとSL/TPを設定できません。また、<strong>ストップレベルが0を返す場合でも実際にはサーバー側で制限がかかるケース</strong>があるため、最低限のマージンを確保するのがポイントです。</p>
<pre><code class="language-mql4">double GetSafeStopDistance()
{
    long   stopLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
    double point     = SymbolInfoDouble(Symbol(), SYMBOL_POINT);

    // ストップレベルが0の場合でも最低10ポイントは確保
    if(stopLevel < 10)
        stopLevel = 10;

    return stopLevel * point;
}

// 使用例：Buy注文のSL/TPを安全に設定
double safeDistance = GetSafeStopDistance();
double sl = Ask - MathMax(desiredSL, safeDistance);
double tp = Ask + MathMax(desiredTP, safeDistance);
</code></pre>
<h3><span id="toc18">③リスクベースのロット計算</span></h3>
<p>口座残高の一定割合をリスクとして、適切なロット数を計算する関数です。</p>
<pre><code class="language-mql4">double CalcLotSize(double riskPercent, double slPoints)
{
    string sym = Symbol();

    double balance   = AccountBalance();
    double riskMoney = balance * riskPercent / 100.0;

    double tickValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
    double tickSize  = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
    double point     = SymbolInfoDouble(sym, SYMBOL_POINT);
    double minLot    = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
    double maxLot    = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
    double lotStep   = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);

    if(tickValue == 0 || tickSize == 0) return minLot;

    // 1ポイントあたりの価値
    double pointValue = tickValue * (point / tickSize);

    // ロット計算
    double lots = riskMoney / (slPoints * pointValue);

    // ロットステップに丸める
    lots = MathFloor(lots / lotStep) * lotStep;

    // 最小・最大ロットでクランプ
    lots = MathMax(lots, minLot);
    lots = MathMin(lots, maxLot);

    return NormalizeDouble(lots, 2);
}
</code></pre>
<h2><span id="toc19">ストラテジーテスターでの注意点</span></h2>
<p>ストラテジーテスター（バックテスト）では、市場情報の取得に制限があります。</p>
<ul>
<li><strong>他の通貨ペアの情報</strong>：テスト対象以外の通貨ペアのMarketInfoやSymbolInfoは、正しい値が返らないことがあります</li>
<li><strong>TickValueが0になる</strong>：テスト開始直後やクロス通貨ペアで、SYMBOL_TRADE_TICK_VALUEが0を返す場合があります</li>
<li><strong>対処法</strong>：TickValueが0の場合はデフォルト値を使う、またはOnTick()内で値が有効になるまで待つ処理を入れましょう</li>
</ul>
<pre><code class="language-mql4">// テスター対策：TickValueが0なら処理をスキップ
void OnTick()
{
    double tickValue = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE);
    if(tickValue <= 0)
    {
        Print("TickValueが無効です。次のティックを待ちます。");
        return;
    }

    // 通常のEAロジック
    // ...
}
</code></pre>
<h2><span id="toc20">まとめ</span></h2>
<p>最後に、この記事のポイントを整理します。</p>
<ol>
<li><strong>MarketInfo関数</strong>はMQL4の基本関数で、MODE定数を使って様々な市場情報をdouble型で取得できる</li>
<li><strong>SymbolInfo系関数</strong>（Double/Integer/String）はデータ型に応じた3つの関数に分かれており、型安全に情報を取得できる</li>
<li><strong>MQL5への移行</strong>を見据えるなら、SymbolInfo系関数を使う習慣をつけるのがおすすめ</li>
<li><strong>ストップレベル</strong>は0を返す場合でも最低限のマージンを確保すると安全</li>
<li><strong>TickValue</strong>を使ったロット計算は実践的なEAに不可欠</li>
<li><strong>ストラテジーテスター</strong>では他通貨ペア情報やTickValueが正しく取得できない場合があるため、ガード処理を入れておくことが大切</li>
</ol>
<p>これらの関数を使いこなせるようになると、ブローカーの取引条件に応じた柔軟なEAが作れるようになります。ぜひ実際にコードを書いて、各関数の返り値を確認してみてください！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13062/%e3%80%90mql4%e3%80%91%e5%b8%82%e5%a0%b4%e6%83%85%e5%a0%b1%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%aa%ac%ef%bc%81marketinfo%e3%83%bbsymbol/">【MQL4】市場情報を取得する関数を完全解説！MarketInfo・SymbolInfoDouble・SymbolInfoInteger・SymbolInfoStringの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4入門】チャートオブジェクト関数を完全攻略！ObjectCreate・ObjectDelete・ObjectSetの使い方</title>
		<link>https://mql-programing.com/archives/13059/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Tue, 21 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【初級編】MQLプログラミング基礎]]></category>
		<category><![CDATA[ObjectDelete]]></category>
		<category><![CDATA[オブジェクト関数]]></category>
		<category><![CDATA[ObjectCreate]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[チャートオブジェクト]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13059</guid>

					<description><![CDATA[<p>MQL4でEAやインジケーターを開発していると、「チャート上に水平線を引きたい」「テキストラベルで情報を表示したい」という場面が必ず出てきます。こうしたチャート上の描画を担うのがチャートオブジェクト関数です。 この記事で [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13059/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5/">【MQL4入門】チャートオブジェクト関数を完全攻略！ObjectCreate・ObjectDelete・ObjectSetの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>MQL4でEAやインジケーターを開発していると、「チャート上に水平線を引きたい」「テキストラベルで情報を表示したい」という場面が必ず出てきます。こうしたチャート上の描画を担うのが<strong>チャートオブジェクト関数</strong>です。</p>
<p>この記事では、<strong>ObjectCreate</strong>・<strong>ObjectDelete</strong>・<strong>ObjectSetInteger</strong>・<strong>ObjectSetDouble</strong>・<strong>ObjectSetString</strong>といった主要関数の使い方を、実践的なコードサンプルとともに徹底解説します。最後には情報パネルを表示するインジケーターの完全コードも用意していますので、ぜひ最後までお読みください。</p>
<h2><span id="toc1">チャートオブジェクト関数とは？</span></h2>
<p>チャートオブジェクト関数とは、MetaTrader 4のチャート上にライン・図形・テキストなどの「オブジェクト」をプログラムから作成・変更・削除するための関数群です。</p>
<p>手動でチャートに水平線やトレンドラインを描くのと同じことを、MQL4のコードから自動的に行えるようになります。EAでエントリーポイントにマークを付けたり、インジケーターで情報パネルを表示したりと、用途は非常に幅広いです。</p>
<h2><span id="toc2">ObjectCreate — オブジェクトを作成する</span></h2>
<p><code>ObjectCreate</code>関数は、チャート上に新しいオブジェクトを作成するための関数です。基本的な書式は以下のとおりです。</p>
<pre><code class="language-mql4">bool ObjectCreate(
    string name,       // オブジェクト名（一意な名前を付ける）
    int    type,       // オブジェクトの種類（ENUM_OBJECT）
    int    sub_window, // サブウィンドウ番号（0=メインチャート）
    datetime time1,    // 第1アンカーポイントの時刻
    double   price1,   // 第1アンカーポイントの価格
    ...                // 必要に応じて第2、第3アンカーポイント
);
</code></pre>
<h3><span id="toc3">主なオブジェクト種類（ENUM_OBJECT）一覧</span></h3>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; width: 100%;">
<thead>
<tr style="background-color: #f0f0f0;">
<th>定数名</th>
<th>説明</th>
<th>アンカーポイント数</th>
</tr>
</thead>
<tbody>
<tr>
<td>OBJ_HLINE</td>
<td>水平線</td>
<td>1（価格のみ）</td>
</tr>
<tr>
<td>OBJ_VLINE</td>
<td>垂直線</td>
<td>1（時刻のみ）</td>
</tr>
<tr>
<td>OBJ_TREND</td>
<td>トレンドライン</td>
<td>2</td>
</tr>
<tr>
<td>OBJ_RECTANGLE</td>
<td>四角形</td>
<td>2</td>
</tr>
<tr>
<td>OBJ_LABEL</td>
<td>テキストラベル（座標指定）</td>
<td>0（ピクセル座標）</td>
</tr>
<tr>
<td>OBJ_TEXT</td>
<td>テキスト（チャート上）</td>
<td>1</td>
</tr>
<tr>
<td>OBJ_ARROW</td>
<td>矢印マーク</td>
<td>1</td>
</tr>
<tr>
<td>OBJ_RECTANGLE_LABEL</td>
<td>四角形ラベル（背景パネル用）</td>
<td>0（ピクセル座標）</td>
</tr>
</tbody>
</table>
<h3><span id="toc4">水平線を作成するサンプル</span></h3>
<p>最もシンプルな例として、現在の価格に水平線を引いてみましょう。</p>
<pre><code class="language-mql4">void CreateHLine()
{
    string name = "MyHLine";
    double price = Ask;

    // 既に同名のオブジェクトがあれば削除
    if(ObjectFind(name) >= 0)
        ObjectDelete(name);

    // 水平線を作成
    ObjectCreate(name, OBJ_HLINE, 0, 0, price);

    // 色を赤に設定
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrRed);

    // チャートを再描画して反映
    ChartRedraw();
}
</code></pre>
<p><code>ObjectCreate</code>は成功すると<code>true</code>、失敗すると<code>false</code>を返します。同じ名前のオブジェクトが既に存在する場合は失敗するため、事前に<code>ObjectFind</code>で確認するか、先に削除しておくのがポイントです。</p>
<h2><span id="toc5">ObjectDelete — オブジェクトを削除する</span></h2>
<p><code>ObjectDelete</code>関数でチャート上のオブジェクトを削除できます。</p>
<pre><code class="language-mql4">// 名前を指定して削除
bool ObjectDelete(string name);

// チャートIDを指定して削除（MQL4でも使用可能）
bool ObjectDelete(long chart_id, string name);
</code></pre>
<h3><span id="toc6">使用例：オブジェクトの削除</span></h3>
<pre><code class="language-mql4">void RemoveMyObjects()
{
    ObjectDelete("MyHLine");
    ObjectDelete("MyLabel");
    ChartRedraw();
}
</code></pre>
<h3><span id="toc7">&#x26a0;&#xfe0f; OnDeinitでの注意点</span></h3>
<p><strong>ObjectDelete関数は非同期で実行されます。</strong>つまり、関数を呼び出した瞬間に削除が完了するとは限りません。特に<code>OnDeinit</code>関数内で呼び出す場合、処理が即座に反映されないことがあります。</p>
<p>確実にオブジェクトを削除したい場合は、<code>ObjectsDeleteAll</code>関数を使うか、<code>ObjectDelete</code>の後に<code>ChartRedraw</code>を呼ぶようにしましょう。</p>
<pre><code class="language-mql4">void OnDeinit(const int reason)
{
    // プレフィックスが一致するオブジェクトを一括削除
    ObjectsDeleteAll(0, "MyPrefix_");
    ChartRedraw();
}
</code></pre>
<p><code>ObjectsDeleteAll</code>の第2引数にプレフィックス（接頭辞）を指定すると、その文字列で始まる名前のオブジェクトだけを一括削除できます。自作オブジェクトに統一のプレフィックスを付ける習慣を身につけると、管理がとても楽になります。</p>
<h2><span id="toc8">ObjectSetInteger — 整数プロパティを設定する</span></h2>
<p><code>ObjectSetInteger</code>関数は、オブジェクトの色・線種・太さなどの整数型プロパティを変更します。</p>
<h3><span id="toc9">よく使うプロパティ一覧</span></h3>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; width: 100%;">
<thead>
<tr style="background-color: #f0f0f0;">
<th>プロパティ定数</th>
<th>説明</th>
<th>設定値の例</th>
</tr>
</thead>
<tbody>
<tr>
<td>OBJPROP_COLOR</td>
<td>オブジェクトの色</td>
<td>clrRed, clrBlue</td>
</tr>
<tr>
<td>OBJPROP_STYLE</td>
<td>線のスタイル</td>
<td>STYLE_SOLID, STYLE_DASH, STYLE_DOT</td>
</tr>
<tr>
<td>OBJPROP_WIDTH</td>
<td>線の太さ</td>
<td>1, 2, 3&#8230;</td>
</tr>
<tr>
<td>OBJPROP_SELECTABLE</td>
<td>ユーザーが選択可能か</td>
<td>true / false</td>
</tr>
<tr>
<td>OBJPROP_HIDDEN</td>
<td>オブジェクトリストに非表示</td>
<td>true / false</td>
</tr>
<tr>
<td>OBJPROP_XDISTANCE</td>
<td>X座標（ピクセル）</td>
<td>10, 20&#8230;</td>
</tr>
<tr>
<td>OBJPROP_YDISTANCE</td>
<td>Y座標（ピクセル）</td>
<td>10, 20&#8230;</td>
</tr>
<tr>
<td>OBJPROP_CORNER</td>
<td>基準コーナー</td>
<td>CORNER_LEFT_UPPER など</td>
</tr>
</tbody>
</table>
<h3><span id="toc10">プロパティ設定のサンプル</span></h3>
<pre><code class="language-mql4">void StyleHLine(string name)
{
    // 色を青に変更
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);

    // 破線スタイルに変更
    ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);

    // 線の太さを2に変更
    ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);

    // ユーザーが選択できないようにする
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);

    // オブジェクトリストに表示しない
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);

    ChartRedraw();
}
</code></pre>
<p><code>OBJPROP_SELECTABLE</code>と<code>OBJPROP_HIDDEN</code>を設定しておくと、ユーザーが誤ってオブジェクトを移動・削除してしまうのを防げます。EA・インジケーターで自動生成するオブジェクトには、これらを設定しておくのがおすすめです。</p>
<h2><span id="toc11">ObjectSetDouble / ObjectGetDouble — 実数プロパティの設定と取得</span></h2>
<p><code>ObjectSetDouble</code>で価格などのdouble型プロパティを設定し、<code>ObjectGetDouble</code>で取得できます。</p>
<pre><code class="language-mql4">// 水平線の価格を変更する
void MoveHLine(string name, double newPrice)
{
    ObjectSetDouble(0, name, OBJPROP_PRICE, newPrice);
    ChartRedraw();
}

// 水平線の現在の価格を取得する
double GetHLinePrice(string name)
{
    return ObjectGetDouble(0, name, OBJPROP_PRICE);
}
</code></pre>
<p>例えば、ユーザーが手動でドラッグした水平線の位置を<code>ObjectGetDouble</code>で読み取り、EAのストップロスやテイクプロフィットに利用するといった活用ができます。</p>
<pre><code class="language-mql4">void OnTick()
{
    // ユーザーが配置した "SL_Line" の価格を取得
    if(ObjectFind("SL_Line") >= 0)
    {
        double slPrice = ObjectGetDouble(0, "SL_Line", OBJPROP_PRICE);
        Print("ストップロス価格: ", slPrice);
    }
}
</code></pre>
<h2><span id="toc12">ObjectSetString — 文字列プロパティを設定する</span></h2>
<p><code>ObjectSetString</code>は、テキスト内容やフォント名などの文字列型プロパティを変更します。<code>OBJ_LABEL</code>や<code>OBJ_TEXT</code>オブジェクトで特によく使います。</p>
<pre><code class="language-mql4">void CreateTextLabel(string name, string text, int x, int y)
{
    if(ObjectFind(name) >= 0)
        ObjectDelete(name);

    // ラベルオブジェクトを作成
    ObjectCreate(name, OBJ_LABEL, 0, 0, 0);

    // 表示位置を設定（ピクセル座標）
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);

    // テキスト内容を設定
    ObjectSetString(0, name, OBJPROP_TEXT, text);

    // フォントを設定
    ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold");

    // フォントサイズと色
    ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 12);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);

    // 選択不可・リスト非表示
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);

    ChartRedraw();
}
</code></pre>
<p><code>OBJ_LABEL</code>はチャートの価格・時刻座標ではなく、<strong>ピクセル座標</strong>で位置を指定するオブジェクトです。<code>OBJPROP_CORNER</code>でどの角を基準にするかを決め、<code>OBJPROP_XDISTANCE</code>と<code>OBJPROP_YDISTANCE</code>でその角からの距離を指定します。チャートをスクロールしても位置が固定されるため、情報表示パネルに最適です。</p>
<h2><span id="toc13">実践サンプル：情報パネルを表示するインジケーター</span></h2>
<p>ここまで学んだ関数を組み合わせて、チャート左上に通貨ペア情報・スプレッド・サーバー時刻を表示する情報パネルインジケーターを作ってみましょう。</p>
<pre><code class="language-mql4">//+------------------------------------------------------------------+
//| InfoPanel.mq4 - 情報パネル表示インジケーター                      |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

// オブジェクト名のプレフィックス
#define PREFIX "InfoPanel_"

//+------------------------------------------------------------------+
//| ラベル作成ヘルパー関数                                            |
//+------------------------------------------------------------------+
void CreateLabel(string name, int x, int y, string text,
                 color clr=clrWhite, int fontSize=11)
{
    string fullName = PREFIX + name;

    if(ObjectFind(fullName) < 0)
        ObjectCreate(fullName, OBJ_LABEL, 0, 0, 0);

    ObjectSetInteger(0, fullName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, fullName, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, fullName, OBJPROP_YDISTANCE, y);
    ObjectSetString(0, fullName, OBJPROP_TEXT, text);
    ObjectSetString(0, fullName, OBJPROP_FONT, "Consolas");
    ObjectSetInteger(0, fullName, OBJPROP_FONTSIZE, fontSize);
    ObjectSetInteger(0, fullName, OBJPROP_COLOR, clr);
    ObjectSetInteger(0, fullName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, fullName, OBJPROP_HIDDEN, true);
}

//+------------------------------------------------------------------+
//| 背景パネル作成関数                                                |
//+------------------------------------------------------------------+
void CreateBackground()
{
    string name = PREFIX + "BG";

    if(ObjectFind(name) < 0)
        ObjectCreate(name, OBJ_RECTANGLE_LABEL, 0, 0, 0);

    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 20);
    ObjectSetInteger(0, name, OBJPROP_XSIZE, 260);
    ObjectSetInteger(0, name, OBJPROP_YSIZE, 100);
    ObjectSetInteger(0, name, OBJPROP_BGCOLOR, C'30,30,50');
    ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);
    ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
    ObjectSetInteger(0, name, OBJPROP_BACK, false);
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}

//+------------------------------------------------------------------+
//| 初期化                                                            |
//+------------------------------------------------------------------+
int OnInit()
{
    CreateBackground();
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| メイン処理                                                        |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &#038;time[],
                const double &#038;open[],
                const double &#038;high[],
                const double &#038;low[],
                const double &#038;close[],
                const long &#038;tick_volume[],
                const long &#038;volume[],
                const int &#038;spread[])
{
    // 通貨ペアと時間足
    string tfStr = "";
    switch(Period())
    {
        case PERIOD_M1:  tfStr = "M1";  break;
        case PERIOD_M5:  tfStr = "M5";  break;
        case PERIOD_M15: tfStr = "M15"; break;
        case PERIOD_M30: tfStr = "M30"; break;
        case PERIOD_H1:  tfStr = "H1";  break;
        case PERIOD_H4:  tfStr = "H4";  break;
        case PERIOD_D1:  tfStr = "D1";  break;
        case PERIOD_W1:  tfStr = "W1";  break;
        case PERIOD_MN1: tfStr = "MN";  break;
        default:         tfStr = "??";  break;
    }
    CreateLabel("Symbol", 20, 28,
                Symbol() + " / " + tfStr,
                clrDodgerBlue, 13);

    // スプレッド
    double spreadPips = MarketInfo(Symbol(), MODE_SPREAD) / 10.0;
    color spreadClr = (spreadPips < 2.0) ? clrLimeGreen : clrOrangeRed;
    CreateLabel("Spread", 20, 52,
                "Spread: " + DoubleToString(spreadPips, 1) + " pips",
                spreadClr, 11);

    // サーバー時刻
    CreateLabel("Time", 20, 75,
                "Server: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
                clrSilver, 10);

    ChartRedraw();
    return(rates_total);
}

//+------------------------------------------------------------------+
//| 終了処理                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, PREFIX);
    ChartRedraw();
}
</code></pre>
<p>このインジケーターをチャートに適用すると、左上にダークブルーの背景パネルが表示され、通貨ペア・時間足・スプレッド・サーバー時刻がリアルタイムで更新されます。スプレッドが2.0pips未満なら緑色、それ以上ならオレンジ色で表示される仕組みです。</p>
<h2><span id="toc14">よくあるミスと対策</span></h2>
<h3><span id="toc15">1. オブジェクト名の重複</span></h3>
<p><code>ObjectCreate</code>は、既に同名のオブジェクトが存在すると<code>false</code>を返して失敗します。オブジェクトを更新したい場合は、先に<code>ObjectFind</code>で存在チェックをするか、<code>ObjectDelete</code>で削除してから再作成しましょう。</p>
<p>上記の実践サンプルのように、既に存在する場合は<code>ObjectCreate</code>をスキップしてプロパティだけ更新するパターンも効率的です。</p>
<h3><span id="toc16">2. ChartRedraw()の呼び忘れ</span></h3>
<p>オブジェクトの作成や変更後に<code>ChartRedraw()</code>を呼ばないと、画面に変更が反映されません。特に<code>OnCalculate</code>や<code>OnTick</code>の中でオブジェクトを操作した場合、最後に必ず<code>ChartRedraw()</code>を呼ぶ習慣をつけましょう。</p>
<pre><code class="language-mql4">// NG: 表示が更新されないことがある
ObjectSetString(0, "label1", OBJPROP_TEXT, "新しいテキスト");

// OK: 確実に画面に反映される
ObjectSetString(0, "label1", OBJPROP_TEXT, "新しいテキスト");
ChartRedraw();
</code></pre>
<h3><span id="toc17">3. OnDeinitでの削除漏れ</span></h3>
<p>インジケーターやEAを削除したとき、作成したオブジェクトがチャートに残ってしまうのはよくあるミスです。<code>OnDeinit</code>関数内で必ずオブジェクトを削除しましょう。</p>
<p>おすすめは、すべてのオブジェクト名に<strong>共通のプレフィックス</strong>を付けて、<code>ObjectsDeleteAll(0, PREFIX)</code>で一括削除する方法です。この方法なら、オブジェクトを追加した際に削除コードの更新を忘れる心配がありません。</p>
<h2><span id="toc18">まとめ</span></h2>
<p>今回はMQL4のチャートオブジェクト関数について解説しました。ポイントを整理します。</p>
<ul>
<li><strong>ObjectCreate</strong>でオブジェクトを作成。同名オブジェクトの存在チェックを忘れずに</li>
<li><strong>ObjectDelete / ObjectsDeleteAll</strong>で削除。プレフィックスを活用した一括削除が便利</li>
<li><strong>ObjectSetInteger</strong>で色・線種・太さ・座標などを設定</li>
<li><strong>ObjectSetDouble / ObjectGetDouble</strong>で価格値の設定・取得</li>
<li><strong>ObjectSetString</strong>でテキスト内容やフォントを変更</li>
<li>操作後は<strong>ChartRedraw()</strong>で画面を再描画</li>
<li><strong>OnDeinit</strong>では必ずオブジェクトを削除して後片付け</li>
</ul>
<p>チャートオブジェクト関数を使いこなせるようになると、EAやインジケーターの視覚的な表現力が大幅にアップします。まずは水平線やテキストラベルなど、シンプルなオブジェクトから試してみてください。慣れてきたら、今回の情報パネルサンプルをベースに、自分だけのカスタムパネルを作ってみましょう！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13059/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5/">【MQL4入門】チャートオブジェクト関数を完全攻略！ObjectCreate・ObjectDelete・ObjectSetの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】デバッグに必須！Print・Alert・Comment・GetLastError・ResetLastErrorの使い方を徹底解説</title>
		<link>https://mql-programing.com/archives/13055/%e3%80%90mql4%e3%80%91%e3%83%87%e3%83%90%e3%83%83%e3%82%b0%e3%81%ab%e5%bf%85%e9%a0%88%ef%bc%81print%e3%83%bbalert%e3%83%bbcomment%e3%83%bbgetlasterror%e3%83%bbresetlasterror%e3%81%ae%e4%bd%bf%e3%81%84/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Mon, 20 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[GetLastError]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[デバッグ]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[Print関数]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13055</guid>

					<description><![CDATA[<p>MQL4でEA（自動売買）やインジケーターを開発するとき、「思った通りに動かない」「どこでエラーが出ているかわからない」という場面は必ず訪れます。そんなときに頼りになるのがデバッグ用の関数たちです。 この記事では、MQL [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13055/%e3%80%90mql4%e3%80%91%e3%83%87%e3%83%90%e3%83%83%e3%82%b0%e3%81%ab%e5%bf%85%e9%a0%88%ef%bc%81print%e3%83%bbalert%e3%83%bbcomment%e3%83%bbgetlasterror%e3%83%bbresetlasterror%e3%81%ae%e4%bd%bf%e3%81%84/">【MQL4】デバッグに必須！Print・Alert・Comment・GetLastError・ResetLastErrorの使い方を徹底解説</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>MQL4でEA（自動売買）やインジケーターを開発するとき、「思った通りに動かない」「どこでエラーが出ているかわからない」という場面は必ず訪れます。そんなときに頼りになるのが<strong>デバッグ用の関数</strong>たちです。</p>
<p>この記事では、MQL4開発で必須となる以下の5つ（＋α）の関数について、基本的な使い方から実践的な注意点まで徹底的に解説します。</p>
<ul>
<li><strong>Print()</strong> — ログへの出力</li>
<li><strong>Comment()</strong> — チャート上への表示</li>
<li><strong>Alert()</strong> — ポップアップ通知</li>
<li><strong>GetLastError()</strong> — エラーコードの取得</li>
<li><strong>ResetLastError()</strong> — エラーコードのリセット</li>
</ul>
<h2><span id="toc1">Print関数 — エキスパートログへの出力</span></h2>
<h3><span id="toc2">基本的な使い方</span></h3>
<p><strong>Print関数</strong>は、MetaTraderの「エキスパート」タブ（ログ）にメッセージを出力する、最も基本的なデバッグ関数です。開発中に変数の値を確認したり、処理の流れを追跡したりするのに欠かせません。</p>
<pre><code class="language-mql4">void OnTick()
{
    double currentPrice = Ask;
    int spread = MarketInfo(Symbol(), MODE_SPREAD);

    Print("現在のAsk価格: ", currentPrice);
    Print("スプレッド: ", spread, " ポイント");
    Print("通貨ペア: ", Symbol(), " 時間足: ", Period());
}
</code></pre>
<p>Print関数はカンマ区切りで複数の値を渡すことができ、<strong>文字列・整数・小数点数</strong>などさまざまなデータ型を自動的に文字列に変換して出力してくれます。</p>
<h3><span id="toc3">データ型ごとの表示仕様</span></h3>
<p>Print関数で各データ型を出力するときの仕様を覚えておきましょう。</p>
<pre><code class="language-mql4">void OnInit()
{
    // 整数型：そのまま数値で表示
    int intValue = 12345;
    Print("int型: ", intValue);           // → int型: 12345

    // double型：小数点以下の桁数は自動調整
    double dblValue = 1.23456789;
    Print("double型: ", dblValue);        // → double型: 1.23456789

    // bool型：trueまたはfalseで表示
    bool boolValue = true;
    Print("bool型: ", boolValue);         // → bool型: true

    // datetime型：日時形式で表示
    datetime dtValue = TimeCurrent();
    Print("datetime型: ", dtValue);       // → datetime型: 2024.01.15 12:30:00
}
</code></pre>
<h3><span id="toc4">出力先について</span></h3>
<p>Print関数の出力先は2か所あります。</p>
<ul>
<li><strong>エキスパートタブ</strong>：MetaTrader画面下部の「エキスパート」タブにリアルタイム表示</li>
<li><strong>ログファイル</strong>：MQL4/Logs フォルダ内にテキストファイルとしても記録される</li>
</ul>
<p>ログファイルに残るため、後から問題を調査するときにも役立ちます。ただし、<strong>OnTick内で大量にPrintを呼ぶとパフォーマンスに影響する</strong>場合があるので、本番稼働時には不要なPrintは削除またはコメントアウトしましょう。</p>
<h2><span id="toc5">Comment関数 — チャート画面への表示</span></h2>
<h3><span id="toc6">基本的な使い方</span></h3>
<p><strong>Comment関数</strong>は、チャートの<strong>左上</strong>にテキストを表示する関数です。リアルタイムで変数の値を視覚的に確認したいときに便利です。</p>
<pre><code class="language-mql4">void OnTick()
{
    double bid = Bid;
    double ask = Ask;
    int spread = (int)((ask - bid) / Point);

    Comment("Bid: ", bid, "\n",
            "Ask: ", ask, "\n",
            "Spread: ", spread, " points\n",
            "Time: ", TimeToStr(TimeCurrent(), TIME_SECONDS));
}
</code></pre>
<p>改行するには<strong>「\n」</strong>を使います。これにより、複数行にわたる情報をきれいに表示できます。</p>
<h3><span id="toc7">Comment関数の重要な注意点</span></h3>
<p>Comment関数には大きな特徴（欠点）があります。<strong>最後に呼び出したComment関数の内容で上書きされる</strong>という点です。</p>
<pre><code class="language-mql4">void OnTick()
{
    Comment("1行目のメッセージ");
    Comment("2行目のメッセージ");  // ← これだけが表示される！
}
</code></pre>
<p>上記の場合、チャートには「2行目のメッセージ」しか表示されません。複数の情報を表示したい場合は、<strong>1回のComment呼び出しにすべての情報をまとめる</strong>必要があります。</p>
<p>また、Comment関数の表示をクリア（消去）したい場合は、空文字を渡します。</p>
<pre><code class="language-mql4">Comment("");  // チャート左上の表示をクリア
</code></pre>
<h2><span id="toc8">Alert関数 — ポップアップ通知</span></h2>
<h3><span id="toc9">基本的な使い方</span></h3>
<p><strong>Alert関数</strong>は、ポップアップダイアログを表示して、音とともにユーザーに通知する関数です。重要なイベント（エントリーシグナル発生、エラー検知など）の通知に使います。</p>
<pre><code class="language-mql4">void OnTick()
{
    static datetime lastAlertTime = 0;
    datetime currentTime = TimeCurrent();

    // RSIが30以下になったらアラート（同じ足で1回だけ）
    double rsi = iRSI(Symbol(), 0, 14, PRICE_CLOSE, 0);

    if(rsi < 30.0 &#038;&#038; lastAlertTime != iTime(Symbol(), 0, 0))
    {
        Alert(Symbol(), " RSIが30以下です！ RSI=", NormalizeDouble(rsi, 2));
        lastAlertTime = iTime(Symbol(), 0, 0);
    }
}
</code></pre>
<h3><span id="toc10">Alert関数の注意点</span></h3>
<p>Alert関数には以下の注意点があります。</p>
<ul>
<li><strong>バックテストでは動作しない</strong>：ストラテジーテスターでのバックテスト時にはAlertは表示されません。バックテスト中のデバッグにはPrint関数を使いましょう。</li>
<li><strong>日本語の一部が文字化けする場合がある</strong>：環境によっては日本語表示が正しくされないことがあります。重要な情報は英数字で出力するのが安全です。</li>
<li><strong>連続呼び出しに注意</strong>：OnTick内で条件なしにAlertを呼ぶと、ティックごとにポップアップが出て操作不能になります。必ず条件制御を入れましょう。</li>
</ul>
<h2><span id="toc11">GetLastError関数 — エラーコードの取得</span></h2>
<h3><span id="toc12">基本的な使い方</span></h3>
<p><strong>GetLastError関数</strong>は、直前の操作で発生したエラーのコード（番号）を取得する関数です。注文送信やファイル操作などの後にエラーチェックを行う際に使います。</p>
<pre><code class="language-mql4">void OnTick()
{
    int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Test", 0, 0, clrBlue);

    if(ticket < 0)
    {
        int errorCode = GetLastError();
        Print("注文エラー！ エラーコード: ", errorCode);
    }
    else
    {
        Print("注文成功！ チケット番号: ", ticket);
    }
}
</code></pre>
<h3><span id="toc13">よく見るエラーコード一覧</span></h3>
<p>以下は、MQL4開発でよく遭遇するエラーコードの一覧です。</p>
<table>
<thead>
<tr>
<th>エラーコード</th>
<th>定数名</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>ERR_NO_ERROR</td>
<td>エラーなし</td>
</tr>
<tr>
<td>1</td>
<td>ERR_NO_RESULT</td>
<td>エラーはないが結果が不明</td>
</tr>
<tr>
<td>2</td>
<td>ERR_COMMON_ERROR</td>
<td>一般的なエラー</td>
</tr>
<tr>
<td>6</td>
<td>ERR_NO_CONNECTION</td>
<td>サーバーとの接続がない</td>
</tr>
<tr>
<td>130</td>
<td>ERR_INVALID_STOPS</td>
<td>ストップが無効（SL/TPが近すぎる等）</td>
</tr>
<tr>
<td>131</td>
<td>ERR_INVALID_TRADE_VOLUME</td>
<td>取引量が無効</td>
</tr>
<tr>
<td>134</td>
<td>ERR_NOT_ENOUGH_MONEY</td>
<td>資金不足</td>
</tr>
<tr>
<td>138</td>
<td>ERR_REQUOTE</td>
<td>リクオート</td>
</tr>
<tr>
<td>146</td>
<td>ERR_TRADE_CONTEXT_BUSY</td>
<td>トレードコンテキストがビジー</td>
</tr>
<tr>
<td>4109</td>
<td>ERR_TRADE_NOT_ALLOWED</td>
<td>自動売買が許可されていない</td>
</tr>
</tbody>
</table>
<h3><span id="toc14">【超重要】GetLastErrorは2度呼ぶとリセットされる！</span></h3>
<p>GetLastError関数には<strong>非常に重要な仕様</strong>があります。<strong>一度呼び出すと、内部のエラーコードが0にリセットされてしまう</strong>のです。</p>
<pre><code class="language-mql4">// ★ ダメな例
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "", 0, 0, clrBlue);
if(ticket < 0)
{
    Print("エラーコード: ", GetLastError());   // ← 1回目：正しいエラーコードが取得できる
    Print("エラーコード: ", GetLastError());   // ← 2回目：0が返る！（リセット済み）
}
</code></pre>
<pre><code class="language-mql4">// ★ 正しい例：変数で受けてから使う
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "", 0, 0, clrBlue);
if(ticket < 0)
{
    int err = GetLastError();  // まず変数に格納！
    Print("エラーコード: ", err);
    Alert("注文失敗 エラー: ", err);  // 何度でも使える
}
</code></pre>
<p>これはMQL4開発でよくあるミスです。<strong>GetLastError()は必ず一度だけ呼び出して変数に保存</strong>してから使いましょう。</p>
<h2><span id="toc15">ResetLastError関数 — エラーコードのリセット</span></h2>
<p><strong>ResetLastError関数</strong>は、定義済み変数<strong>_LastError</strong>に格納されているエラーコードを<strong>0（エラーなし）にリセット</strong>するための関数です。</p>
<pre><code class="language-mql4">void OnTick()
{
    // エラーコードを事前にリセット
    ResetLastError();

    int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Test", 0, 0, clrBlue);

    if(ticket < 0)
    {
        int err = GetLastError();
        Print("注文エラー: ", err);
    }
}
</code></pre>
<h3><span id="toc16">なぜリセットが必要なのか？</span></h3>
<p>GetLastError()は「最後に発生したエラー」を返します。つまり、以前の処理で発生したエラーコードが残っている可能性があるのです。特定の処理のエラーだけを正確に検知したい場合は、<strong>処理の直前にResetLastError()を呼ぶのが定石</strong>です。</p>
<pre><code class="language-mql4">// 定石パターン：リセット → 処理 → エラーチェック
ResetLastError();           // ① リセット
bool result = OrderClose(ticket, lots, price, 3, clrRed);  // ② 処理実行
int err = GetLastError();   // ③ エラー取得（変数に格納）
if(err != 0)
{
    Print("決済エラー: ", err);
}
</code></pre>
<h2><span id="toc17">ErrorDescription関数 — エラーコードを文章に変換</span></h2>
<p>エラーコードの番号だけでは、何が起きたのかすぐにはわかりません。そこで便利なのが<strong>ErrorDescription関数</strong>です。この関数を使うと、エラーコードを人間が読める英語の文章に変換できます。</p>
<p>ただし、この関数はMQL4に標準で組み込まれているわけではなく、<strong>stdlib.mqh</strong>というライブラリファイルをインクルードする必要があります。</p>
<pre><code class="language-mql4">#include &lt;stdlib.mqh&gt;  // ErrorDescription関数を使うために必要

void OnTick()
{
    ResetLastError();

    int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Test", 0, 0, clrBlue);

    if(ticket < 0)
    {
        int err = GetLastError();
        Print("エラーコード: ", err, " 内容: ", ErrorDescription(err));
        // 例：エラーコード: 134 内容: not enough money
    }
}
</code></pre>
<p>エラーの原因がすぐにわかるため、デバッグの効率が格段に上がります。<strong>ぜひstdlib.mqhのインクルードを習慣にしましょう。</strong></p>
<h2><span id="toc18">実践例 — 5つの関数を組み合わせたデバッグ付きEA</span></h2>
<p>ここまで学んだ関数を組み合わせた、実践的なサンプルコードをご紹介します。</p>
<pre><code class="language-mql4">#include &lt;stdlib.mqh&gt;

input double LotSize = 0.1;
input int MagicNumber = 12345;

void OnTick()
{
    // 現在の状態をチャートに表示
    Comment("=== デバッグ情報 ===\n",
            "通貨ペア: ", Symbol(), "\n",
            "Bid: ", Bid, "  Ask: ", Ask, "\n",
            "スプレッド: ", MarketInfo(Symbol(), MODE_SPREAD), "\n",
            "保有ポジション: ", CountOrders(), "\n",
            "口座残高: ", AccountBalance(), "\n",
            "更新時刻: ", TimeToStr(TimeCurrent(), TIME_SECONDS));

    // 簡単な売買ロジック（例：移動平均のクロス）
    double maFast = iMA(Symbol(), 0, 10, 0, MODE_SMA, PRICE_CLOSE, 0);
    double maFastPrev = iMA(Symbol(), 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
    double maSlow = iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 0);
    double maSlowPrev = iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 1);

    // ゴールデンクロスで買い
    if(maFastPrev <= maSlowPrev &#038;&#038; maFast > maSlow && CountOrders() == 0)
    {
        Print("ゴールデンクロス検出！ 買い注文を送信します。");
        Print("MA(10)=", maFast, " MA(25)=", maSlow);

        ResetLastError();  // エラーをリセット
        int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, 0, 0,
                               "MA Cross Buy", MagicNumber, 0, clrBlue);

        int err = GetLastError();  // 変数に格納（1回だけ呼ぶ！）

        if(ticket >= 0)
        {
            Print("注文成功！ チケット: ", ticket);
        }
        else
        {
            Print("注文失敗！ エラーコード: ", err,
                  " 内容: ", ErrorDescription(err));
            Alert("注文失敗！ Error: ", err, " ", ErrorDescription(err));
        }
    }
}

// 保有ポジション数をカウントする関数
int CountOrders()
{
    int count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
                count++;
        }
    }
    return count;
}
</code></pre>
<p>このサンプルでは、以下のようにデバッグ関数を使い分けています。</p>
<ul>
<li><strong>Comment</strong>：リアルタイムの状態監視（チャート上に常時表示）</li>
<li><strong>Print</strong>：処理の流れやシグナル検出の記録（ログに残る）</li>
<li><strong>Alert</strong>：注文失敗などの重要イベントの即時通知</li>
<li><strong>ResetLastError → GetLastError</strong>：正確なエラーコード取得の定石パターン</li>
<li><strong>ErrorDescription</strong>：エラー内容の可読化</li>
</ul>
<h2><span id="toc19">まとめ — デバッグ関数の使い分け</span></h2>
<p>最後に、各関数の特徴と使い分けを表で整理します。</p>
<table>
<thead>
<tr>
<th>関数名</th>
<th>出力先</th>
<th>主な用途</th>
<th>注意点</th>
</tr>
</thead>
<tbody>
<tr>
<td>Print()</td>
<td>エキスパートログ</td>
<td>変数の値確認、処理フロー追跡</td>
<td>大量出力でパフォーマンス低下</td>
</tr>
<tr>
<td>Comment()</td>
<td>チャート左上</td>
<td>リアルタイムの状態監視</td>
<td>最後の呼び出しで上書きされる</td>
</tr>
<tr>
<td>Alert()</td>
<td>ポップアップ</td>
<td>重要イベントの即時通知</td>
<td>バックテスト非対応・日本語文字化けの可能性</td>
</tr>
<tr>
<td>GetLastError()</td>
<td>—</td>
<td>エラーコード取得</td>
<td><strong>2度呼ぶとリセットされる</strong>（変数で受ける）</td>
</tr>
<tr>
<td>ResetLastError()</td>
<td>—</td>
<td>エラーコードの初期化</td>
<td>処理前にリセットするのが定石</td>
</tr>
</tbody>
</table>
<p>デバッグ関数を上手に使いこなすことは、MQL4開発の効率を大きく左右します。特に<strong>「GetLastErrorは変数で一度受けてから使う」</strong>と<strong>「処理前にResetLastErrorでリセットする」</strong>の2つは、ぜひ今日から実践してください。</p>
<p>デバッグの精度が上がれば、EA開発のスピードも自然と上がっていきますよ！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13055/%e3%80%90mql4%e3%80%91%e3%83%87%e3%83%90%e3%83%83%e3%82%b0%e3%81%ab%e5%bf%85%e9%a0%88%ef%bc%81print%e3%83%bbalert%e3%83%bbcomment%e3%83%bbgetlasterror%e3%83%bbresetlasterror%e3%81%ae%e4%bd%bf%e3%81%84/">【MQL4】デバッグに必須！Print・Alert・Comment・GetLastError・ResetLastErrorの使い方を徹底解説</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】配列関数を完全マスター！ArraySize・ArrayResize・ArraySort・ArrayCopy・ArrayInitialize・ArraySetAsSeriesの使い方</title>
		<link>https://mql-programing.com/archives/13052/%e3%80%90mql4%e3%80%91%e9%85%8d%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81arraysize%e3%83%bbarrayresize%e3%83%bbarraysort%e3%83%bbarraycopy/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Sun, 19 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[ArraySetAsSeries]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[配列関数]]></category>
		<category><![CDATA[ArrayResize]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13052</guid>

					<description><![CDATA[<p>MQL4で自動売買（EA）やカスタムインジケーターを開発するとき、配列の操作は避けて通れません。価格データの格納、インジケーター値の計算、ソートによるランキング処理など、あらゆる場面で配列関数が活躍します。 この記事では [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13052/%e3%80%90mql4%e3%80%91%e9%85%8d%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81arraysize%e3%83%bbarrayresize%e3%83%bbarraysort%e3%83%bbarraycopy/">【MQL4】配列関数を完全マスター！ArraySize・ArrayResize・ArraySort・ArrayCopy・ArrayInitialize・ArraySetAsSeriesの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>MQL4で自動売買（EA）やカスタムインジケーターを開発するとき、<strong>配列の操作</strong>は避けて通れません。価格データの格納、インジケーター値の計算、ソートによるランキング処理など、あらゆる場面で配列関数が活躍します。</p>
<p>この記事では、MQL4で特に使用頻度の高い<strong>6つの配列関数</strong>を体系的に解説します。</p>
<ul>
<li><strong>ArraySize()</strong> – 要素数の取得</li>
<li><strong>ArrayResize()</strong> – サイズの動的変更</li>
<li><strong>ArrayInitialize()</strong> – 全要素の一括初期化</li>
<li><strong>ArrayCopy()</strong> – 配列のコピー</li>
<li><strong>ArraySort()</strong> – ソート（並び替え）</li>
<li><strong>ArraySetAsSeries()</strong> – 時系列インデックスへの変換</li>
</ul>
<p>それぞれの関数について、基本的な使い方・注意点・実践的なコードサンプルを交えながら丁寧に解説していきます。</p>
<h2><span id="toc1">ArraySize() – 配列の要素数を取得する</span></h2>
<p><code>ArraySize()</code>は、配列に含まれる<strong>全要素数</strong>を返す関数です。ループ処理で配列の全要素を走査するときに欠かせません。</p>
<h3><span id="toc2">基本構文</span></h3>
<pre><code class="language-mql5">int ArraySize(
   const void&amp; array[]   // 対象の配列
);
</code></pre>
<h3><span id="toc3">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double prices[5] = {100.0, 101.5, 102.3, 99.8, 100.7};

   int size = ArraySize(prices);
   Print("要素数: ", size);  // 出力: 要素数: 5

   // ループ処理での活用
   for(int i = 0; i &lt; ArraySize(prices); i++)
   {
      Print("prices[", i, "] = ", prices[i]);
   }
}
</code></pre>
<h3><span id="toc4">多次元配列での注意点</span></h3>
<p><code>ArraySize()</code>は多次元配列に対しては、<strong>全次元の要素数の積（全要素数）</strong>を返します。特定の次元の要素数だけを知りたい場合は<code>ArrayRange()</code>を使いましょう。</p>
<pre><code class="language-mql5">void OnStart()
{
   double matrix[3][4];  // 3行4列の二次元配列

   Print("ArraySize: ", ArraySize(matrix));       // 出力: 12（3×4）
   Print("第1次元: ", ArrayRange(matrix, 0));      // 出力: 3
   Print("第2次元: ", ArrayRange(matrix, 1));      // 出力: 4
}
</code></pre>
<h2><span id="toc5">ArrayResize() – 配列のサイズを動的に変更する</span></h2>
<p><code>ArrayResize()</code>は、<strong>動的配列</strong>のサイズを変更する関数です。EAの運用中にデータが増減する場面で大活躍します。</p>
<h3><span id="toc6">基本構文</span></h3>
<pre><code class="language-mql5">int ArrayResize(
   void&amp; array[],         // サイズ変更する配列
   int    new_size,        // 新しいサイズ
   int    reserve_size=0   // 予約サイズ（省略可）
);
</code></pre>
<p>戻り値は、成功した場合は新しいサイズ、失敗した場合は<strong>-1</strong>です。</p>
<h3><span id="toc7">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double data[];  // 動的配列（サイズ未指定）

   // サイズを5に設定
   ArrayResize(data, 5);
   Print("サイズ: ", ArraySize(data));  // 出力: 5

   // データを格納
   for(int i = 0; i &lt; 5; i++)
      data[i] = i * 1.5;

   // サイズを10に拡張（既存データは保持される）
   ArrayResize(data, 10);
   Print("拡張後サイズ: ", ArraySize(data));  // 出力: 10
   Print("data[2] = ", data[2]);  // 出力: 3.0（既存データは保持）
}
</code></pre>
<h3><span id="toc8">reserve_sizeでパフォーマンスを改善する</span></h3>
<p>ループ内で何度も<code>ArrayResize()</code>を呼ぶと、メモリの再割り当てが頻繁に発生しパフォーマンスが低下します。第3引数の<code>reserve_size</code>を指定することで、あらかじめメモリを多めに確保し、再割り当ての回数を減らせます。</p>
<pre><code class="language-mql5">void OnStart()
{
   double ticks[];
   int count = 0;

   // 悪い例：毎回メモリ再割り当てが発生
   // for(int i = 0; i &lt; 10000; i++)
   // {
   //    ArrayResize(ticks, ++count);
   //    ticks[count - 1] = Bid;
   // }

   // 良い例：reserve_sizeで事前にメモリを確保
   for(int i = 0; i &lt; 10000; i++)
   {
      ArrayResize(ticks, ++count, 10000);  // 最大10000要素分を予約
      ticks[count - 1] = Bid;
   }
}
</code></pre>
<p>大量のデータを扱うEAでは、この<code>reserve_size</code>の指定が処理速度に大きく影響します。ぜひ覚えておきましょう。</p>
<h2><span id="toc9">ArrayInitialize() – 全要素を一括で初期化する</span></h2>
<p><code>ArrayInitialize()</code>は、配列の<strong>全要素を指定した値で一括初期化</strong>する関数です。</p>
<h3><span id="toc10">基本構文</span></h3>
<pre><code class="language-mql5">int ArrayInitialize(
   double&amp; array[],   // 初期化する配列
   double  value       // セットする値
);
</code></pre>
<h3><span id="toc11">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double buffer[10];

   // 全要素を0.0で初期化
   ArrayInitialize(buffer, 0.0);

   for(int i = 0; i &lt; ArraySize(buffer); i++)
      Print("buffer[", i, "] = ", buffer[i]);  // すべて0.0
}
</code></pre>
<h3><span id="toc12">ArrayResizeとの組み合わせが重要</span></h3>
<p><code>ArrayResize()</code>でサイズを拡張した直後、新しく追加された要素の値は<strong>不定（ゴミ値）</strong>です。そのため、拡張後に<code>ArrayInitialize()</code>で初期化するのが安全なパターンです。</p>
<pre><code class="language-mql5">void OnStart()
{
   double data[];

   ArrayResize(data, 10);
   ArrayInitialize(data, 0.0);  // 拡張後は必ず初期化！

   Print("data[5] = ", data[5]);  // 安全に0.0が入っている
}
</code></pre>
<h2><span id="toc13">ArrayCopy() – 配列を別の配列にコピーする</span></h2>
<p><code>ArrayCopy()</code>は、配列の全体または一部を別の配列にコピーする関数です。</p>
<h3><span id="toc14">基本構文</span></h3>
<pre><code class="language-mql5">int ArrayCopy(
   void&amp; dst_array[],      // コピー先
   const void&amp; src_array[], // コピー元
   int   dst_start=0,       // コピー先の開始位置
   int   src_start=0,       // コピー元の開始位置
   int   count=WHOLE_ARRAY  // コピーする要素数
);
</code></pre>
<p>戻り値はコピーされた要素数です。</p>
<h3><span id="toc15">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double source[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
   double dest[];

   // 全要素をコピー（destは自動でリサイズされる）
   ArrayCopy(dest, source);
   Print("dest[2] = ", dest[2]);  // 出力: 3.3

   // 部分コピー：sourceのインデックス1から3要素をdest2のインデックス0にコピー
   double dest2[3];
   ArrayCopy(dest2, source, 0, 1, 3);
   // dest2 = {2.2, 3.3, 4.4}
   for(int i = 0; i &lt; ArraySize(dest2); i++)
      Print("dest2[", i, "] = ", dest2[i]);
}
</code></pre>
<p>部分コピーを使いこなすと、直近N本のデータだけを抜き出す処理などが簡潔に書けます。</p>
<h2><span id="toc16">ArraySort() – 配列をソート（並び替え）する</span></h2>
<p><code>ArraySort()</code>は、配列の要素を<strong>昇順</strong>にソートする関数です。</p>
<h3><span id="toc17">基本構文</span></h3>
<pre><code class="language-mql5">bool ArraySort(
   void&amp; array[]   // ソートする配列
);
</code></pre>
<p>MQL4の<code>ArraySort()</code>は<strong>昇順のみ</strong>に対応しています。</p>
<h3><span id="toc18">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double values[5] = {3.5, 1.2, 4.8, 2.1, 3.9};

   // 昇順ソート
   ArraySort(values);

   for(int i = 0; i &lt; ArraySize(values); i++)
      Print("values[", i, "] = ", values[i]);
   // 出力: 1.2, 2.1, 3.5, 3.9, 4.8
}
</code></pre>
<h3><span id="toc19">降順にしたい場合</span></h3>
<p>MQL4の<code>ArraySort()</code>には降順オプションがないため、昇順ソート後に逆順で読むか、別の配列に逆順コピーする方法を使います。</p>
<pre><code class="language-mql5">void OnStart()
{
   double values[5] = {3.5, 1.2, 4.8, 2.1, 3.9};

   // まず昇順ソート
   ArraySort(values);

   // 逆順で読み取ることで降順として扱う
   int size = ArraySize(values);
   for(int i = size - 1; i &gt;= 0; i--)
      Print("降順 values[", (size - 1 - i), "] = ", values[i]);
   // 出力: 4.8, 3.9, 3.5, 2.1, 1.2
}
</code></pre>
<h3><span id="toc20">注意点：時系列配列はソートできない</span></h3>
<p><code>ArraySetAsSeries()</code>で時系列フラグが設定された配列は、<code>ArraySort()</code>でソートできません。ソートしたい場合は、まず通常の配列にコピーしてからソートしましょう。</p>
<h2><span id="toc21">ArraySetAsSeries() – 時系列インデックスに変換する</span></h2>
<p><code>ArraySetAsSeries()</code>は、配列のインデックスの方向を<strong>時系列方向</strong>に変更する関数です。MetaTraderのチャートデータは最新のバー（ローソク足）がインデックス0になっていますが、通常の配列は先頭がインデックス0です。この違いを吸収するのがこの関数です。</p>
<h3><span id="toc22">基本構文</span></h3>
<pre><code class="language-mql5">bool ArraySetAsSeries(
   const void&amp; array[],  // 対象の配列
   bool        flag       // true=時系列, false=通常
);
</code></pre>
<h3><span id="toc23">通常配列と時系列配列の違い</span></h3>
<pre><code class="language-mql5">// 通常の配列（左から右へインデックスが増加）
// index:  [0]  [1]  [2]  [3]  [4]
// データ:  古い ←――――――――――→ 新しい

// 時系列配列（右から左へインデックスが増加）
// index:  [4]  [3]  [2]  [1]  [0]
// データ:  古い ←――――――――――→ 新しい
</code></pre>
<h3><span id="toc24">基本的な使い方</span></h3>
<pre><code class="language-mql5">void OnStart()
{
   double closeArray[];

   // 直近10本の終値を取得
   ArraySetAsSeries(closeArray, true);  // 時系列方向に設定
   CopyClose(Symbol(), PERIOD_CURRENT, 0, 10, closeArray);

   // closeArray[0] = 最新バーの終値
   // closeArray[1] = 1つ前のバーの終値
   // closeArray[9] = 9つ前のバーの終値
   Print("最新の終値: ", closeArray[0]);
   Print("1つ前の終値: ", closeArray[1]);
}
</code></pre>
<h3><span id="toc25">インジケーター開発での活用</span></h3>
<p>カスタムインジケーターの<code>OnCalculate()</code>関数では、引数として渡される価格配列のインデックス方向が不定の場合があります。そのため、関数の冒頭で<code>ArraySetAsSeries()</code>を呼んでインデックス方向を統一するのが定番のパターンです。</p>
<pre><code class="language-mql5">int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &amp;time[],
                const double &amp;open[],
                const double &amp;high[],
                const double &amp;low[],
                const double &amp;close[],
                const long &amp;tick_volume[],
                const long &amp;volume[],
                const int &amp;spread[])
{
   // インデックス方向を時系列に統一
   ArraySetAsSeries(close, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);

   // これで close[0] が最新バーの終値になる
   // ... インジケーターの計算処理 ...

   return(rates_total);
}
</code></pre>
<h2><span id="toc26">実践テクニック：6つの関数を組み合わせて使う</span></h2>
<p>ここまで学んだ6つの関数を組み合わせた実践的なサンプルを見てみましょう。直近N本のバーから<strong>最高値トップ3</strong>を抽出する処理です。</p>
<pre><code class="language-mql5">void OnStart()
{
   int period = 20;  // 直近20本のバーを対象

   // 1. 高値データを格納する動的配列を準備
   double highPrices[];
   ArrayResize(highPrices, period);       // サイズを設定
   ArrayInitialize(highPrices, 0.0);      // 初期化

   // 2. 直近の高値データを取得
   double tempHigh[];
   ArraySetAsSeries(tempHigh, true);      // 時系列方向に設定
   CopyHigh(Symbol(), PERIOD_CURRENT, 0, period, tempHigh);

   // 3. 作業用配列にコピー
   ArrayCopy(highPrices, tempHigh, 0, 0, period);

   // 4. 昇順ソートしてトップ3を取得（末尾3要素が最大値）
   ArraySort(highPrices);

   int size = ArraySize(highPrices);
   Print("=== 直近", period, "本の高値トップ3 ===");
   for(int i = 0; i &lt; 3; i++)
   {
      Print("第", (i + 1), "位: ", highPrices[size - 1 - i]);
   }
}
</code></pre>
<p>このように、<code>ArrayResize</code>→<code>ArrayInitialize</code>→<code>ArraySetAsSeries</code>→<code>ArrayCopy</code>→<code>ArraySort</code>→<code>ArraySize</code>と、6つの関数を自然に組み合わせて使えるようになると、実践的なEA開発がスムーズに進みます。</p>
<h2><span id="toc27">配列関数 早見表</span></h2>
<table>
<thead>
<tr>
<th>関数名</th>
<th>機能</th>
<th>主な使用場面</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ArraySize()</strong></td>
<td>要素数を取得</td>
<td>ループの上限値、配列が空かの判定</td>
</tr>
<tr>
<td><strong>ArrayResize()</strong></td>
<td>サイズを動的に変更</td>
<td>データ数が実行時に決まる場合</td>
</tr>
<tr>
<td><strong>ArrayInitialize()</strong></td>
<td>全要素を一括初期化</td>
<td>ArrayResize後のゴミ値対策</td>
</tr>
<tr>
<td><strong>ArrayCopy()</strong></td>
<td>配列の全体/部分コピー</td>
<td>データのバックアップ、部分抽出</td>
</tr>
<tr>
<td><strong>ArraySort()</strong></td>
<td>昇順ソート</td>
<td>ランキング処理、中央値の算出</td>
</tr>
<tr>
<td><strong>ArraySetAsSeries()</strong></td>
<td>インデックス方向を時系列に変換</td>
<td>インジケーター開発、価格データ操作</td>
</tr>
</tbody>
</table>
<h2><span id="toc28">まとめ</span></h2>
<p>今回はMQL4の主要な配列関数6つについて解説しました。ポイントを振り返りましょう。</p>
<ul>
<li><strong>ArraySize()</strong>はループ処理の必須パートナー。多次元配列では全要素数が返る点に注意</li>
<li><strong>ArrayResize()</strong>は第3引数の<code>reserve_size</code>を活用してパフォーマンスを改善</li>
<li><strong>ArrayInitialize()</strong>はArrayResize後のゴミ値を防ぐために必ずセットで使う</li>
<li><strong>ArrayCopy()</strong>は部分コピーが便利。引数の順番（コピー先が最初）を間違えないように</li>
<li><strong>ArraySort()</strong>はMQL4では昇順のみ。降順が必要なら逆順で読み取る</li>
<li><strong>ArraySetAsSeries()</strong>はインジケーター開発の定番。<code>close[0]</code>を最新バーにするために使う</li>
</ul>
<p>これら6つの関数を使いこなせれば、EA開発やインジケーター作成の幅が大きく広がります。まずは実際にスクリプトやEAの中で試してみて、配列操作に慣れていきましょう！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13052/%e3%80%90mql4%e3%80%91%e9%85%8d%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81arraysize%e3%83%bbarrayresize%e3%83%bbarraysort%e3%83%bbarraycopy/">【MQL4】配列関数を完全マスター！ArraySize・ArrayResize・ArraySort・ArrayCopy・ArrayInitialize・ArraySetAsSeriesの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】文字列関数を完全マスター！StringFormat・DoubleToString・IntegerToString・StringLen・StringSubstrの使い方</title>
		<link>https://mql-programing.com/archives/13049/%e3%80%90mql4%e3%80%91%e6%96%87%e5%ad%97%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81stringformat%e3%83%bbdoubletostring%e3%83%bbintegertostring/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Sat, 18 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[文字列関数]]></category>
		<category><![CDATA[StringFormat]]></category>
		<category><![CDATA[DoubleToString]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13049</guid>

					<description><![CDATA[<p>EA開発をしていると、「ログに価格やチケット番号を表示したい」「コメント欄にきれいな書式で情報を出力したい」という場面が頻繁にあります。そんなとき活躍するのが文字列関数です。 MQL4には多くの文字列関数が用意されていま [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13049/%e3%80%90mql4%e3%80%91%e6%96%87%e5%ad%97%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81stringformat%e3%83%bbdoubletostring%e3%83%bbintegertostring/">【MQL4】文字列関数を完全マスター！StringFormat・DoubleToString・IntegerToString・StringLen・StringSubstrの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>EA開発をしていると、「ログに価格やチケット番号を表示したい」「コメント欄にきれいな書式で情報を出力したい」という場面が頻繁にあります。そんなとき活躍するのが<strong>文字列関数</strong>です。</p>
<p>MQL4には多くの文字列関数が用意されていますが、この記事では特に使用頻度の高い<strong>5つの関数</strong>に絞って解説します。</p>
<ul>
<li><strong>DoubleToString</strong> — 実数を文字列に変換</li>
<li><strong>IntegerToString</strong> — 整数を文字列に変換</li>
<li><strong>StringFormat</strong> — 書式を指定して文字列を生成</li>
<li><strong>StringLen</strong> — 文字列の長さを取得</li>
<li><strong>StringSubstr</strong> — 文字列の一部を切り出す</li>
</ul>
<p>すべてサンプルコード付きで、最後には5関数を組み合わせた実践例も紹介します。それでは順番に見ていきましょう！</p>
<h2><span id="toc1">DoubleToString — 実数を文字列に変換する</span></h2>
<p><code>DoubleToString</code>は、double型の数値を指定した小数桁数の文字列に変換する関数です。価格やロット数の表示に欠かせません。</p>
<h3><span id="toc2">基本的な使い方</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    double price = 145.123456;

    // 小数点以下3桁で表示
    string s1 = DoubleToString(price, 3);
    Print("3桁: ", s1);  // 出力: 145.123

    // 小数点以下5桁で表示
    string s2 = DoubleToString(price, 5);
    Print("5桁: ", s2);  // 出力: 145.12346（四捨五入される）
}
</code></pre>
<h3><span id="toc3">実践テクニック：_Digits との組み合わせ</span></h3>
<p>通貨ペアによって小数桁数は異なります（USDJPYは3桁、EURUSDは5桁など）。<code>_Digits</code>を使えば、通貨ペアに応じた桁数で自動的に変換できます。</p>
<pre><code class="language-mql4">void OnTick()
{
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    // 通貨ペアに合った桁数で文字列化
    string priceStr = DoubleToString(bid, _Digits);
    Print(_Symbol, " の現在価格: ", priceStr);
}
</code></pre>
<p>この書き方なら、どの通貨ペアのチャートにEAを適用しても正しい桁数で価格が表示されます。</p>
<h2><span id="toc4">IntegerToString — 整数を文字列に変換する</span></h2>
<p><code>IntegerToString</code>は、整数を文字列に変換する関数です。単純な変換だけでなく、<strong>ゼロ埋め（パディング）</strong>もできるのが特徴です。</p>
<h3><span id="toc5">基本的な使い方</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    int ticket = 12345;

    // 単純な変換
    string s1 = IntegerToString(ticket);
    Print("チケット: ", s1);  // 出力: 12345
}
</code></pre>
<h3><span id="toc6">ゼロ埋め（パディング）の使い方</span></h3>
<p><code>IntegerToString</code>の第2引数で桁数、第3引数で埋める文字を指定できます。ログの整形やファイル名の連番に便利です。</p>
<pre><code class="language-mql4">void OnStart()
{
    int num = 42;

    // 6桁にゼロ埋め
    string s1 = IntegerToString(num, 6, '0');
    Print("ゼロ埋め: ", s1);  // 出力: 000042

    // 8桁にスペース埋め（デフォルト）
    string s2 = IntegerToString(num, 8);
    Print("スペース埋め: [", s2, "]");  // 出力: [      42]
}
</code></pre>
<h2><span id="toc7">StringFormat — 書式指定で文字列を組み立てる</span></h2>
<p><code>StringFormat</code>はC言語の<code>sprintf</code>に相当する関数で、<strong>最も万能な文字列生成関数</strong>です。複数の値をひとつの文字列にまとめたいときに大活躍します。</p>
<h3><span id="toc8">主な書式指定子</span></h3>
<table>
<thead>
<tr>
<th>指定子</th>
<th>意味</th>
<th>例</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>%s</code></td>
<td>文字列</td>
<td>&#8220;USDJPY&#8221;</td>
</tr>
<tr>
<td><code>%d</code></td>
<td>整数</td>
<td>12345</td>
</tr>
<tr>
<td><code>%f</code></td>
<td>実数（デフォルト6桁）</td>
<td>145.123000</td>
</tr>
<tr>
<td><code>%.Nf</code></td>
<td>実数（小数N桁）</td>
<td>145.12（N=2の場合）</td>
</tr>
<tr>
<td><code>%%</code></td>
<td>%そのもの</td>
<td>%</td>
</tr>
</tbody>
</table>
<h3><span id="toc9">サンプルコード</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    string symbol = "USDJPY";
    double price  = 145.678;
    int    ticket  = 99001;
    double lots   = 0.1;

    // 書式を指定して一気に文字列生成
    string msg = StringFormat("%s | Ticket:%d | Price:%.3f | Lots:%.2f",
                              symbol, ticket, price, lots);
    Print(msg);
    // 出力: USDJPY | Ticket:99001 | Price:145.678 | Lots:0.10
}
</code></pre>
<p><code>StringFormat</code>を使えば、文字列の連結（<code>+</code>演算子）を多用するよりもコードがすっきりします。特に3つ以上の値を組み合わせるときはStringFormatがおすすめです。</p>
<h2><span id="toc10">StringLen — 文字列の長さを取得する</span></h2>
<p><code>StringLen</code>は文字列の文字数を返す関数です。入力値のバリデーションや空文字チェックに使います。</p>
<h3><span id="toc11">基本的な使い方</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    string text = "Hello MQL4";
    int len = StringLen(text);
    Print("文字数: ", len);  // 出力: 10（スペースも1文字）

    // 空文字チェック
    string comment = "";
    if(StringLen(comment) == 0)
    {
        Print("コメントは空です");
    }
}
</code></pre>
<h3><span id="toc12">実践テクニック：入力パラメータのチェック</span></h3>
<pre><code class="language-mql4">input string MagicPrefix = "EA01";

int OnInit()
{
    // プレフィックスが長すぎないかチェック
    if(StringLen(MagicPrefix) > 10)
    {
        Print("エラー: MagicPrefixは10文字以内にしてください");
        return INIT_PARAMETERS_INCORRECT;
    }
    return INIT_SUCCEEDED;
}
</code></pre>
<h2><span id="toc13">StringSubstr — 文字列の一部を切り出す</span></h2>
<p><code>StringSubstr</code>は文字列から指定位置・指定長さの部分文字列を取り出す関数です。日時文字列の分解やファイル名の加工に活用できます。</p>
<h3><span id="toc14">基本的な使い方</span></h3>
<pre><code class="language-mql4">void OnStart()
{
    string text = "2024.01.15 09:30:00";

    // 日付部分を取得（先頭から10文字）
    string datePart = StringSubstr(text, 0, 10);
    Print("日付: ", datePart);  // 出力: 2024.01.15

    // 時刻部分を取得（11文字目から最後まで）
    string timePart = StringSubstr(text, 11);
    Print("時刻: ", timePart);  // 出力: 09:30:00

    // 年だけ取得（先頭から4文字）
    string year = StringSubstr(text, 0, 4);
    Print("年: ", year);  // 出力: 2024
}
</code></pre>
<p>第2引数が<strong>開始位置</strong>（0始まり）、第3引数が<strong>切り出す文字数</strong>です。第3引数を省略すると、開始位置から末尾までの全文字が返されます。</p>
<h3><span id="toc15">実践テクニック：末尾N文字を切り出す関数</span></h3>
<p>StringLenとStringSubstrを組み合わせると、末尾から指定文字数を取り出すユーティリティ関数が作れます。</p>
<pre><code class="language-mql4">// 末尾n文字を取得する関数
string StringRight(string text, int n)
{
    int len = StringLen(text);
    if(n >= len) return text;
    return StringSubstr(text, len - n, n);
}

void OnStart()
{
    string filename = "report_2024.csv";
    string ext = StringRight(filename, 4);
    Print("拡張子: ", ext);  // 出力: .csv
}
</code></pre>
<h2><span id="toc16">実践例：5つの関数を組み合わせた注文ログ出力</span></h2>
<p>最後に、ここまで学んだ5つの関数を全て使った実践的なサンプルを紹介します。注文情報をきれいに整形してログ出力する関数です。</p>
<pre><code class="language-mql4">// 注文情報を整形して出力する関数
void PrintOrderInfo(int ticket)
{
    if(!OrderSelect(ticket, SELECT_BY_TICKET))
    {
        Print("チケット ", IntegerToString(ticket), " が見つかりません");
        return;
    }

    string symbol   = OrderSymbol();
    int    type     = OrderType();
    double lots     = OrderLots();
    double openPrice = OrderOpenPrice();
    string comment  = OrderComment();

    // IntegerToString: チケット番号をゼロ埋め
    string ticketStr = IntegerToString(ticket, 8, '0');

    // DoubleToString: 価格を通貨ペアに合った桁数で変換
    int digits = (int)MarketInfo(symbol, MODE_DIGITS);
    string priceStr = DoubleToString(openPrice, digits);

    // StringLen: コメントが空なら代替テキストを設定
    if(StringLen(comment) == 0)
        comment = "(コメントなし)";

    // StringSubstr: コメントが長すぎる場合は20文字に切り詰め
    if(StringLen(comment) > 20)
        comment = StringSubstr(comment, 0, 20) + "...";

    // StringFormat: 全体を整形
    string typeStr = (type == OP_BUY) ? "BUY" : "SELL";
    string log = StringFormat("[%s] %s %s %.2fLots @ %s Comment:%s",
                              ticketStr, symbol, typeStr,
                              lots, priceStr, comment);
    Print(log);
    // 出力例: [00012345] USDJPY BUY 0.10Lots @ 145.678 Comment:MyEA_Entry
}
</code></pre>
<p>このように、文字列関数を組み合わせることで<strong>読みやすく情報量の多いログ</strong>が簡単に作れます。デバッグ効率が格段に上がるので、ぜひ活用してください。</p>
<h2><span id="toc17">まとめ</span></h2>
<p>今回紹介した5つの文字列関数のポイントを整理します。</p>
<table>
<thead>
<tr>
<th>関数名</th>
<th>用途</th>
<th>覚えておきたいポイント</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>DoubleToString</strong></td>
<td>実数→文字列</td>
<td><code>_Digits</code>と組み合わせて通貨ペア対応</td>
</tr>
<tr>
<td><strong>IntegerToString</strong></td>
<td>整数→文字列</td>
<td>第2・第3引数でゼロ埋め（パディング）可能</td>
</tr>
<tr>
<td><strong>StringFormat</strong></td>
<td>書式指定で文字列生成</td>
<td><code>%s</code><code>%d</code><code>%.Nf</code>を使い分ける</td>
</tr>
<tr>
<td><strong>StringLen</strong></td>
<td>文字列の長さ取得</td>
<td>空文字チェックやバリデーションに活用</td>
</tr>
<tr>
<td><strong>StringSubstr</strong></td>
<td>部分文字列の切り出し</td>
<td>開始位置は0始まり、第3引数省略で末尾まで</td>
</tr>
</tbody>
</table>
<p>これらの関数はEA開発のあらゆる場面で登場します。特に<strong>StringFormat</strong>は使いこなせると、Print文やComment表示が一気にスマートになります。まずはサンプルコードをコピーして動かしてみるところから始めてみてください！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13049/%e3%80%90mql4%e3%80%91%e6%96%87%e5%ad%97%e5%88%97%e9%96%a2%e6%95%b0%e3%82%92%e5%ae%8c%e5%85%a8%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%81stringformat%e3%83%bbdoubletostring%e3%83%bbintegertostring/">【MQL4】文字列関数を完全マスター！StringFormat・DoubleToString・IntegerToString・StringLen・StringSubstrの使い方</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4入門】iClose・iOpen・iHigh・iLow・iTimeで過去のローソク足データを取得しよう</title>
		<link>https://mql-programing.com/archives/13046/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91iclose%e3%83%bbiopen%e3%83%bbihigh%e3%83%bbilow%e3%83%bbitime%e3%81%a7%e9%81%8e%e5%8e%bb%e3%81%ae%e3%83%ad%e3%83%bc%e3%82%bd%e3%82%af%e8%b6%b3%e3%83%87%e3%83%bc/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【初級編】MQLプログラミング基礎]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[ローソク足]]></category>
		<category><![CDATA[iClose]]></category>
		<category><![CDATA[iOpen]]></category>
		<category><![CDATA[時系列アクセス関数]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13046</guid>

					<description><![CDATA[<p>EA（自動売買プログラム）やカスタムインジケーターを作るとき、「過去のローソク足の価格を取得したい」という場面は非常に多く出てきます。たとえば「1本前の足が陽線だったら買い」「直近5本の高値の中で最も高い価格を調べたい」 [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13046/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91iclose%e3%83%bbiopen%e3%83%bbihigh%e3%83%bbilow%e3%83%bbitime%e3%81%a7%e9%81%8e%e5%8e%bb%e3%81%ae%e3%83%ad%e3%83%bc%e3%82%bd%e3%82%af%e8%b6%b3%e3%83%87%e3%83%bc/">【MQL4入門】iClose・iOpen・iHigh・iLow・iTimeで過去のローソク足データを取得しよう</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>EA（自動売買プログラム）やカスタムインジケーターを作るとき、「過去のローソク足の価格を取得したい」という場面は非常に多く出てきます。たとえば「1本前の足が陽線だったら買い」「直近5本の高値の中で最も高い価格を調べたい」など、ローソク足データの取得はMQL4プログラミングの基本中の基本です。</p>
<p>この記事では、MQL4でローソク足の<strong>始値・終値・高値・安値・開始時刻</strong>を取得するための5つの関数――<code>iOpen()</code>、<code>iClose()</code>、<code>iHigh()</code>、<code>iLow()</code>、<code>iTime()</code>の使い方を、サンプルコード付きでわかりやすく解説します。</p>
<h2><span id="toc1">5つの時系列アクセス関数の概要</span></h2>
<p>MQL4には、ローソク足（バー）の価格情報を取得するための<strong>時系列アクセス関数</strong>が用意されています。iOpen関数は指定した通貨ペア・時間軸・バーシフトに対応するバーの始値を、iClose関数は終値を、iHigh関数は高値を、iLow関数は安値を返す関数です。それぞれの役割は以下のとおりです。</p>
<table border="1" cellpadding="8" cellspacing="0" style="border-collapse: collapse; width: 100%; margin: 1em 0;">
<thead>
<tr style="background-color: #f0f0f0;">
<th>関数名</th>
<th>取得できる値</th>
<th>戻り値の型</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>iOpen()</code></td>
<td>指定バーの<strong>始値</strong>（Open）</td>
<td>double</td>
</tr>
<tr>
<td><code>iClose()</code></td>
<td>指定バーの<strong>終値</strong>（Close）</td>
<td>double</td>
</tr>
<tr>
<td><code>iHigh()</code></td>
<td>指定バーの<strong>高値</strong>（High）</td>
<td>double</td>
</tr>
<tr>
<td><code>iLow()</code></td>
<td>指定バーの<strong>安値</strong>（Low）</td>
<td>double</td>
</tr>
<tr>
<td><code>iTime()</code></td>
<td>指定バーの<strong>形成開始時刻</strong></td>
<td>datetime</td>
</tr>
</tbody>
</table>
<p>5つの関数はすべて<strong>同じ引数の構成</strong>を持っており、一度覚えればすべてすぐに使いこなせます。</p>
<h2><span id="toc2">関数の書式と引数の意味</span></h2>
<p>ここでは<code>iClose()</code>を例に解説しますが、他の4つの関数もまったく同じ形式です。</p>
<pre><code class="language-mql5">double iClose(
    string symbol,    // 通貨ペア名
    int    timeframe, // 時間軸
    int    shift      // バーの位置（シフト）
);
</code></pre>
<h3><span id="toc3">① symbol（通貨ペア名）</span></h3>
<p>通貨ペア名は「気配値表示ウィンドウ」に表示されているとおりに記述します。特定の通貨ペア名を指定せず、EA等を適用したチャートの通貨ペアの終値を取得したい場合は、「NULL」と記述します。</p>
<ul>
<li><code>NULL</code> または <code>Symbol()</code> → EAやインジケーターを適用中のチャートの通貨ペア</li>
<li><code>"USDJPY"</code> → ドル円を明示的に指定</li>
<li><code>"EURUSD"</code> → ユーロドルを明示的に指定</li>
</ul>
<p>通貨ペアを直接記述するとどの通貨ペアチャートにセットしてもその通貨ペアを強制的にトレードしてしまうため、Symbol()と記述しましょう。</p>
<h3><span id="toc4">② timeframe（時間軸）</span></h3>
<p>どの時間足のデータを取得するかを指定します。<code>0</code>またはPERIOD定数を使います。</p>
<table border="1" cellpadding="8" cellspacing="0" style="border-collapse: collapse; width: 100%; margin: 1em 0;">
<thead>
<tr style="background-color: #f0f0f0;">
<th>定数</th>
<th>値</th>
<th>時間足</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>PERIOD_CURRENT</code></td>
<td>0</td>
<td>現在のチャートの時間足</td>
</tr>
<tr>
<td><code>PERIOD_M1</code></td>
<td>1</td>
<td>1分足</td>
</tr>
<tr>
<td><code>PERIOD_M5</code></td>
<td>5</td>
<td>5分足</td>
</tr>
<tr>
<td><code>PERIOD_M15</code></td>
<td>15</td>
<td>15分足</td>
</tr>
<tr>
<td><code>PERIOD_M30</code></td>
<td>30</td>
<td>30分足</td>
</tr>
<tr>
<td><code>PERIOD_H1</code></td>
<td>60</td>
<td>1時間足</td>
</tr>
<tr>
<td><code>PERIOD_H4</code></td>
<td>240</td>
<td>4時間足</td>
</tr>
<tr>
<td><code>PERIOD_D1</code></td>
<td>1440</td>
<td>日足</td>
</tr>
<tr>
<td><code>PERIOD_W1</code></td>
<td>10080</td>
<td>週足</td>
</tr>
<tr>
<td><code>PERIOD_MN1</code></td>
<td>43200</td>
<td>月足</td>
</tr>
</tbody>
</table>
<p><code>0</code>を指定すると、EAやインジケーターを適用しているチャートの時間足が自動的に使われます。マルチタイムフレーム分析（MTF）を行いたい場合は、ここに上位足の定数を明示的に指定します。</p>
<h3><span id="toc5">③ shift（バーの位置）</span></h3>
<p>終値を取得したいバーが現在のバーであれば「０」、１本前のバーであれば「１」、２本前のバーであれば「２」……と記述します。</p>
<ul>
<li><code>0</code> → 現在（最新）のバー</li>
<li><code>1</code> → 1本前のバー</li>
<li><code>2</code> → 2本前のバー</li>
<li><code>n</code> → n本前のバー</li>
</ul>
<p>同じ記述でも時間が進むにつれて値が変化します。数字が大きくなるほど過去のバーを参照します。なお、<strong>shift=0の最新バーはまだ形成中</strong>なので、確定した値を使いたい場合はshift=1以降を使うのが一般的です。</p>
<h2><span id="toc6">基本的な使い方 ― 各関数のサンプルコード</span></h2>
<p>まずは5つの関数それぞれを使って、ログにローソク足情報を出力する基本例を見てみましょう。</p>
<pre><code class="language-mql5">//+------------------------------------------------------------------+
//| 各時系列アクセス関数の基本的な使い方                                 |
//+------------------------------------------------------------------+
#property strict

void OnInit()
{
    // 1本前（確定済み）のバーの各値を取得
    double openPrice  = iOpen(NULL, 0, 1);
    double closePrice = iClose(NULL, 0, 1);
    double highPrice  = iHigh(NULL, 0, 1);
    double lowPrice   = iLow(NULL, 0, 1);
    datetime barTime  = iTime(NULL, 0, 1);

    Print("=== 1本前のローソク足情報 ===");
    Print("開始時刻: ", TimeToString(barTime, TIME_DATE | TIME_MINUTES));
    Print("始値:     ", DoubleToString(openPrice, Digits));
    Print("高値:     ", DoubleToString(highPrice, Digits));
    Print("安値:     ", DoubleToString(lowPrice, Digits));
    Print("終値:     ", DoubleToString(closePrice, Digits));
}
</code></pre>
<p>このコードをEAとしてコンパイルし、チャートにセットすると、「エキスパート」タブに1本前のバーの情報が表示されます。<code>NULL</code>と<code>0</code>を指定しているので、適用したチャートの通貨ペアと時間足のデータが自動的に使われます。</p>
<h2><span id="toc7">実践サンプル① ― 陽線・陰線を判定する</span></h2>
<p>EA開発でよく使うのが「前のローソク足が陽線だったか陰線だったか」の判定です。始値と終値を比較するだけで簡単に実現できます。</p>
<pre><code class="language-mql5">//+------------------------------------------------------------------+
//| 1本前のローソク足が陽線か陰線かを判定                               |
//+------------------------------------------------------------------+
void OnTick()
{
    double prevOpen  = iOpen(Symbol(), 0, 1);
    double prevClose = iClose(Symbol(), 0, 1);

    if(prevClose > prevOpen)
    {
        // 陽線（終値 > 始値）
        Print("1本前は陽線です（上昇）");
    }
    else if(prevClose < prevOpen)
    {
        // 陰線（終値 < 始値）
        Print("1本前は陰線です（下降）");
    }
    else
    {
        // 同値（十字線など）
        Print("1本前は同値線です");
    }
}
</code></pre>
<p>「2本連続で陽線なら買いエントリー」といった条件も、shift=1とshift=2を使って簡単に書けます。</p>
<h2><span id="toc8">実践サンプル② ― 直近N本の最高値・最安値を求める</span></h2>
<p>forループとiHigh/iLowを組み合わせれば、直近N本のバーの中から最高値・最安値を見つけることができます。</p>
<pre><code class="language-mql5">//+------------------------------------------------------------------+
//| 直近N本のバーから最高値・最安値を算出                                |
//+------------------------------------------------------------------+
void OnTick()
{
    int lookback = 20;  // 過去20本分を調べる
    double highest = 0;
    double lowest  = 999999;

    for(int i = 1; i <= lookback; i++)
    {
        double h = iHigh(NULL, 0, i);
        double l = iLow(NULL, 0, i);

        if(h > highest) highest = h;
        if(l < lowest)  lowest  = l;
    }

    Print("直近", lookback, "本の最高値: ", DoubleToString(highest, Digits));
    Print("直近", lookback, "本の最安値: ", DoubleToString(lowest, Digits));
}
</code></pre>
<p>※ブレイクアウト戦略やレンジ判定のロジックに応用できます。</p>
<h2><span id="toc9">実践サンプル③ ― マルチタイムフレーム（MTF）で上位足の値を取得</span></h2>
<p>「チャートの時間足を切り替えても、常に4時間足のオープン時間を取得したい！」という場合にはiTime()関数を使用して引数に「PERIOD_H4」を渡してあげる必要があります。また、EAやインジケーターを適用したチャートの通貨ペアはUSD/JPYだが、取得したい情報がEUR/JPYのものである場合でもiTime()関数が活躍します。これは他のiClose()、iHigh()なども同様です。</p>
<pre><code class="language-mql5">//+------------------------------------------------------------------+
//| 5分足チャート上から日足・4時間足のデータを取得する例                   |
//+------------------------------------------------------------------+
void OnTick()
{
    // 日足の1本前の終値
    double dailyClose = iClose(NULL, PERIOD_D1, 1);
    // 4時間足の1本前の高値
    double h4High     = iHigh(NULL, PERIOD_H4, 1);
    // 4時間足の1本前の安値
    double h4Low      = iLow(NULL, PERIOD_H4, 1);
    // 日足の1本前の開始時刻
    datetime dailyTime = iTime(NULL, PERIOD_D1, 1);

    Print("前日の終値: ", DoubleToString(dailyClose, Digits));
    Print("前日の開始時刻: ", TimeToString(dailyTime, TIME_DATE));
    Print("4H前回バーの高値: ", DoubleToString(h4High, Digits));
    Print("4H前回バーの安値: ", DoubleToString(h4Low, Digits));
}
</code></pre>
<p>たとえば5分足チャート上で「前日の高値・安値」をラインとして引いたり、「4時間足が上昇トレンドなら5分足で押し目買いだけを行う」といったMTFロジックを組むときに活躍します。</p>
<h2><span id="toc10">定義済み配列 Open[] / Close[] / High[] / Low[] / Time[] との違い</span></h2>
<p>MQL4には、i〇〇()関数とは別に、<code>Open[]</code>、<code>Close[]</code>、<code>High[]</code>、<code>Low[]</code>、<code>Time[]</code>という<strong>定義済み配列</strong>も用意されています。EA等を適用したチャートにおける終値は定義済み配列であるClose[]に格納されており、EA等を適用したチャートにおける終値を取得したい場合はClose[]を使用し、EA等を適用したチャート以外の通貨ペアや時間軸における終値を取得したい場合はiClose()関数を使用します。使い分けのポイントは次のとおりです。</p>
<table border="1" cellpadding="8" cellspacing="0" style="border-collapse: collapse; width: 100%; margin: 1em 0;">
<thead>
<tr style="background-color: #f0f0f0;">
<th></th>
<th>定義済み配列<br />（例: <code>Close[1]</code>）</th>
<th>i〇〇()関数<br />（例: <code>iClose(NULL,0,1)</code>）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>通貨ペア</strong></td>
<td>チャートの通貨ペアのみ</td>
<td>任意の通貨ペアを指定可能</td>
</tr>
<tr>
<td><strong>時間足</strong></td>
<td>チャートの時間足のみ</td>
<td>任意の時間足を指定可能</td>
</tr>
<tr>
<td><strong>記述の簡潔さ</strong></td>
<td>短くシンプル</td>
<td>引数が3つ必要</td>
</tr>
<tr>
<td><strong>MTF対応</strong></td>
<td>×</td>
<td>○</td>
</tr>
</tbody>
</table>
<p>なお、<code>iClose(NULL, 0, 1)</code>と<code>Close[1]</code>は同じ値を返します。どちらを使っても結果は同じですが、後からMTF対応に拡張する可能性がある場合は、最初からi〇〇()関数で書いておくと修正が楽です。</p>
<h2><span id="toc11">よくある注意点・落とし穴</span></h2>
<h3><span id="toc12">shift=0 は未確定のバー</span></h3>
<p><code>iClose(NULL, 0, 0)</code> で取得できる終値は、<strong>現在形成中のバーの最新価格</strong>です。ティックが入るたびに値が変わるため、売買判断には確定済みのshift=1を使うのが安全です。</p>
<h3><span id="toc13">ローカル履歴がない場合は0が返る</span></h3>
<p>ローカル履歴がない（読み込まれていない）場合、関数は0を返します。特にマルチタイムフレームや他通貨ペアのデータを使う場合は、事前にヒストリーデータを取得しておきましょう。</p>
<h3><span id="toc14">Symbol()を使おう</span></h3>
<p>通貨ペア名は<code>"USDJPY"</code>のように直接書くこともできますが、<code>Symbol()</code>や<code>NULL</code>を使えば、どのチャートにセットしても自動的にそのチャートの通貨ペアが適用されるので、汎用性の高いEAが作れます。</p>
<h2><span id="toc15">まとめ</span></h2>
<p>今回学んだ5つの時系列アクセス関数をおさらいしましょう。</p>
<ul>
<li><code>iOpen(symbol, timeframe, shift)</code> → 始値を取得</li>
<li><code>iClose(symbol, timeframe, shift)</code> → 終値を取得</li>
<li><code>iHigh(symbol, timeframe, shift)</code> → 高値を取得</li>
<li><code>iLow(symbol, timeframe, shift)</code> → 安値を取得</li>
<li><code>iTime(symbol, timeframe, shift)</code> → バーの形成開始時刻を取得</li>
</ul>
<p>すべて<strong>同じ3つの引数（通貨ペア・時間軸・バー位置）</strong>で統一されているため、1つ覚えれば残りもすぐに使えます。</p>
<p>これらの関数は、陽線・陰線の判定、ブレイクアウト戦略、マルチタイムフレーム分析など、EA開発のあらゆる場面で必要になります。ぜひサンプルコードを実際にMT4のMetaEditorに入力して動かし、手を動かしながら身につけていきましょう！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13046/%e3%80%90mql4%e5%85%a5%e9%96%80%e3%80%91iclose%e3%83%bbiopen%e3%83%bbihigh%e3%83%bbilow%e3%83%bbitime%e3%81%a7%e9%81%8e%e5%8e%bb%e3%81%ae%e3%83%ad%e3%83%bc%e3%82%bd%e3%82%af%e8%b6%b3%e3%83%87%e3%83%bc/">【MQL4入門】iClose・iOpen・iHigh・iLow・iTimeで過去のローソク足データを取得しよう</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】iCustom関数の使い方を徹底解説！カスタムインジケーターをEAから呼び出す方法とサンプルコード</title>
		<link>https://mql-programing.com/archives/13043/%e3%80%90mql4%e3%80%91icustom%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%a0%e3%82%a4%e3%83%b3%e3%82%b8/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Thu, 16 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[注文関係]]></category>
		<category><![CDATA[EA自動売買]]></category>
		<category><![CDATA[iCustom]]></category>
		<category><![CDATA[カスタムインジケーター]]></category>
		<category><![CDATA[サンプルコード]]></category>
		<category><![CDATA[MQL4]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13043</guid>

					<description><![CDATA[<p>「お気に入りのインジケーターを使って自動売買したい！」——そんな夢を叶えてくれるのが、MQL4のiCustom関数です。 iCustom関数を使えば、MT4のIndicatorsフォルダにあるカスタムインジケーターの値を [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13043/%e3%80%90mql4%e3%80%91icustom%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%a0%e3%82%a4%e3%83%b3%e3%82%b8/">【MQL4】iCustom関数の使い方を徹底解説！カスタムインジケーターをEAから呼び出す方法とサンプルコード</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>「お気に入りのインジケーターを使って自動売買したい！」——そんな夢を叶えてくれるのが、MQL4の<strong>iCustom関数</strong>です。</p>
<p>iCustom関数を使えば、MT4の<strong>Indicatorsフォルダにあるカスタムインジケーターの値をEA（エキスパートアドバイザー）から自由に取得</strong>できます。つまり、チャート上で矢印やラインを表示するインジケーターのシグナルを、そのまま自動売買のロジックに組み込めるのです。</p>
<p>この記事では、iCustom関数の基本的な構文から、実践的なサンプルコードまで、初心者にもわかりやすく解説していきます。</p>
<h2><span id="toc1">iCustom関数とは？</span></h2>
<p>iCustom関数は、<strong>指定したカスタムインジケーターの計算結果（バッファの値）を取得する</strong>MQL4の組み込み関数です。</p>
<p>MT4にはiMA（移動平均線）やiRSI（RSI）など、標準インジケーター用の関数が用意されていますが、自作のインジケーターやネットで配布されているインジケーターにはこうした専用関数がありません。そこで活躍するのがiCustom関数です。</p>
<p>iCustom関数を利用すると、Indicatorsフォルダに保存されているあらゆるカスタムインジケーターの値を取得できます。これにより、インジケーターのシグナルをEAのエントリー条件・決済条件として使うことが可能になります。</p>
<h2><span id="toc2">iCustom関数の構文（シンタックス）</span></h2>
<p>iCustom関数の基本構文は以下の通りです。</p>
<pre><code class="language-mql4">double iCustom(
    string symbol,      // 通貨ペア（NULLで現在のチャート）
    int    timeframe,    // 時間足（0で現在の時間足）
    string name,         // カスタムインジケーター名
    ...                  // インジケーターの入力パラメーター（可変）
    int    mode,         // バッファ番号（0〜7）
    int    shift         // 取得するバーの位置（0が最新）
);
</code></pre>
<p>各パラメーターの意味を詳しく見ていきましょう。</p>
<h3><span id="toc3">① symbol（通貨ペア）</span></h3>
<p>値を取得したい通貨ペアを文字列で指定します。現在のチャートの通貨ペアを指定する場合は <code>NULL</code> または <code>_Symbol</code> を使います。別の通貨ペアを指定したい場合は <code>"USDJPY"</code> のように気配値表示ウィンドウの表記通りに記述します。</p>
<h3><span id="toc4">② timeframe（時間足）</span></h3>
<p>時間軸の種類を指定します。現在のチャートの時間足を使う場合は <code>0</code> または <code>PERIOD_CURRENT</code> を指定します。別の時間足を指定する場合は、以下の定数を使います。</p>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse; margin: 16px 0;">
<tr style="background-color: #f0f0f0;">
<th>定数</th>
<th>値</th>
<th>意味</th>
</tr>
<tr>
<td>PERIOD_M1</td>
<td>1</td>
<td>1分足</td>
</tr>
<tr>
<td>PERIOD_M5</td>
<td>5</td>
<td>5分足</td>
</tr>
<tr>
<td>PERIOD_M15</td>
<td>15</td>
<td>15分足</td>
</tr>
<tr>
<td>PERIOD_M30</td>
<td>30</td>
<td>30分足</td>
</tr>
<tr>
<td>PERIOD_H1</td>
<td>60</td>
<td>1時間足</td>
</tr>
<tr>
<td>PERIOD_H4</td>
<td>240</td>
<td>4時間足</td>
</tr>
<tr>
<td>PERIOD_D1</td>
<td>1440</td>
<td>日足</td>
</tr>
<tr>
<td>PERIOD_W1</td>
<td>10080</td>
<td>週足</td>
</tr>
<tr>
<td>PERIOD_MN1</td>
<td>43200</td>
<td>月足</td>
</tr>
</table>
<h3><span id="toc5">③ name（インジケーター名）</span></h3>
<p>カスタムインジケーター名を文字列で指定します。指定するカスタムインジケーターの.ex4ファイルが、MQL4\Indicatorsフォルダまたはそのサブフォルダに保存されている必要があります。</p>
<p>サブディレクトリに配置されている場合は、&#8221;サブディレクトリ名\\カスタムインジケータ名&#8221;で指定します。</p>
<pre><code class="language-mql4">// Indicatorsフォルダ直下の場合
iCustom(NULL, 0, "MyIndicator", ...);

// サブフォルダ「Examples」内の場合
iCustom(NULL, 0, "Examples\\MyIndicator", ...);
</code></pre>
<h3><span id="toc6">④ &#8230;（インジケーターの入力パラメーター）</span></h3>
<p>カスタムインジケータの入力パラメータです。渡された入力パラメータの順序は、カスタムインジケータの宣言順に対応する必要があります。ここが一番混乱しやすいポイントです。</p>
<p>パラメーターを省略した場合は、インジケーター側のデフォルト値が使用されます。ただし、<strong>途中のパラメーターだけを省略することはできません</strong>。変更したいパラメーターより前のパラメーターは、すべてデフォルト値であっても記述する必要があります。</p>
<h3><span id="toc7">⑤ mode（バッファ番号）</span></h3>
<p>取得したいインジケーターバッファのインデックス番号（0〜7）を指定します。最初のバッファはmode=0です。</p>
<p>例えば、ボリンジャーバンドのようなインジケーターなら：</p>
<ul>
<li>バッファ0：ミドルバンド</li>
<li>バッファ1：アッパーバンド</li>
<li>バッファ2：ロワーバンド</li>
</ul>
<p>のように対応します。バッファ番号の確認方法は後述します。</p>
<h3><span id="toc8">⑥ shift（バーの位置）</span></h3>
<p>カスタムインジケーターの値を取得したいバーの位置を指定します。現在のバーであれば「0」、1本前のバーであれば「1」、2本前のバーであれば「2」と記述します。</p>
<p>EA内では、確定した値を使うため <code>shift=1</code>（1本前の確定バー）を指定するのが一般的です。</p>
<h2><span id="toc9">バッファ番号の調べ方</span></h2>
<p>iCustom関数を使ううえで最も重要なのが、<strong>正しいバッファ番号を知ること</strong>です。バッファ番号を間違えると、まったく違う値を取得してしまいます。</p>
<h3><span id="toc10">方法1：チャート上でマウスカーソルを合わせる</span></h3>
<p>チャート上にセットしたインジケーターのラインや矢印にマウスカーソルをのせて、Value1やValue2などという表示がでれば、iCustomでEA化できます。</p>
<h3><span id="toc11">方法2：データウィンドウで確認する</span></h3>
<p>MT4の<strong>「表示」→「データウィンドウ」</strong>を開くと、各インジケーターのバッファ値が一覧で表示されます。上から順に0, 1, 2&#8230;のバッファ番号に対応しています。</p>
<h3><span id="toc12">方法3：ソースコードを確認する</span></h3>
<p>インジケーターの.mq4ファイルがある場合は、<code>SetIndexBuffer()</code> や <code>SetIndexLabel()</code> の記述からバッファ番号を確認できます。</p>
<pre><code class="language-mql4">// ソースコードの例
SetIndexBuffer(0, UpperBuffer);  // バッファ0 → アッパーライン
SetIndexBuffer(1, LowerBuffer);  // バッファ1 → ロワーライン
SetIndexBuffer(2, BuySignal);    // バッファ2 → 買いシグナル
SetIndexBuffer(3, SellSignal);   // バッファ3 → 売りシグナル
</code></pre>
<h2><span id="toc13">基本的な使い方：サンプルコード</span></h2>
<p>ここからは、実際のサンプルコードを使って使い方を解説します。</p>
<h3><span id="toc14">サンプル1：移動平均線カスタムインジケーターの値を取得</span></h3>
<p>まずは、最もシンプルな例です。カスタムインジケーター「MyMA」の値を取得してチャートにコメント表示します。</p>
<pre><code class="language-mql4">void OnTick()
{
    // MyMAインジケーターの値を取得（期間20、バッファ0、1本前のバー）
    double ma_value = iCustom(NULL, 0, "MyMA", 20, 0, 1);
    
    // チャートにコメント表示
    Comment("MyMA(20)の値: ", DoubleToString(ma_value, Digits));
}
</code></pre>
<h3><span id="toc15">サンプル2：ボリンジャーバンドカスタムインジケーターの複数バッファを取得</span></h3>
<p>iCustom関数でボリンジャーバンドの値を取得する例です。</p>
<pre><code class="language-mql4">void OnTick()
{
    // Bandsインジケーターの各バンドを取得
    int period = 20;
    double deviation = 2.0;
    
    double upper = iCustom(NULL, 0, "Bands", period, 0, deviation, 1, 0);  // アッパーバンド（バッファ1）
    double lower = iCustom(NULL, 0, "Bands", period, 0, deviation, 2, 0);  // ロワーバンド（バッファ2）
    
    Comment("Upper: ", upper, "\nLower: ", lower);
}
</code></pre>
<h3><span id="toc16">サンプル3：矢印シグナルインジケーターでEA化する</span></h3>
<p>これが最も実践的な使い方です。買い矢印・売り矢印を表示するインジケーターのシグナルを使って自動売買するEAのサンプルです。</p>
<pre><code class="language-mql4">#property strict

// --- 入力パラメーター ---
input double Lots       = 0.01;    // ロット数
input int    MagicNumber = 12345;  // マジックナンバー
input int    StopLoss    = 50;     // ストップロス（pips）
input int    TakeProfit  = 100;    // テイクプロフィット（pips）

void OnTick()
{
    // --- カスタムインジケーターのシグナル取得 ---
    // 買いシグナル（バッファ0）と売りシグナル（バッファ1）を1本前のバーから取得
    double buySignal  = iCustom(NULL, 0, "MySignalIndicator", 0, 1);
    double sellSignal = iCustom(NULL, 0, "MySignalIndicator", 1, 1);
    
    // --- 現在のポジション数をカウント ---
    int buyCount = 0, sellCount = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
        if(OrderType() == OP_BUY)  buyCount++;
        if(OrderType() == OP_SELL) sellCount++;
    }
    
    // --- 買いエントリー ---
    // シグナルが EMPTY_VALUE でなければ矢印が出現している
    if(buySignal != EMPTY_VALUE && buySignal != 0 && buyCount == 0)
    {
        double sl = Ask - StopLoss * Point * 10;
        double tp = Ask + TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, sl, tp,
                               "iCustom Buy", MagicNumber, 0, clrBlue);
        if(ticket < 0)
            Print("買い注文エラー: ", GetLastError());
    }
    
    // --- 売りエントリー ---
    if(sellSignal != EMPTY_VALUE &#038;&#038; sellSignal != 0 &#038;&#038; sellCount == 0)
    {
        double sl = Bid + StopLoss * Point * 10;
        double tp = Bid - TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, sl, tp,
                               "iCustom Sell", MagicNumber, 0, clrRed);
        if(ticket < 0)
            Print("売り注文エラー: ", GetLastError());
    }
}
</code></pre>
<p>ポイントは、<strong>矢印が表示されていないバーでは <code>EMPTY_VALUE</code>（空の値）が返される</strong>という点です。矢印系のシグナルインジケーターをEA化する場合、この <code>EMPTY_VALUE</code> との比較がエントリー判定の基本パターンになります。</p>
<h2><span id="toc17">iCustom関数を使う際の注意点</span></h2>
<h3><span id="toc18">1. .ex4ファイルが必要</span></h3>
<p>iCustom関数が参照するのは、コンパイル済みの<strong>.ex4ファイル</strong>です。ソースコード（.mq4）だけではなく、必ずコンパイルして.ex4ファイルを生成しておきましょう。</p>
<h3><span id="toc19">2. バッファレスインジケーターには使えない</span></h3>
<p>オシレーター系のインジケーターの場合はバッファが不可欠なので問題ないのですが、メインチャートに表示される矢印系のインジケーターの場合にはバッファで処理していないことがあります。「バッファでシグナルを処理するようにプログラミングしていないこと」、これがiCustomでインジケーターをEA化できない原因です。バッファレスインジケーターはiCustomではEA化できません。</p>
<h3><span id="toc20">3. パラメーターの順序と型に注意</span></h3>
<p>入力パラメーターは<strong>インジケーターのソースコードで宣言された順番通り</strong>に指定する必要があります。順番を間違えたり、型が合わないと正しい値が返りません。</p>
<h3><span id="toc21">4. パフォーマンスを意識する</span></h3>
<p>iCustom関数は呼び出すたびに計算が実行されるため、ティックごとに何度も呼び出すとパフォーマンスが低下します。新しいバーが確定したタイミングでのみ呼び出し、データをキャッシュすると処理速度を改善できます。</p>
<pre><code class="language-mql4">// 新しいバーの判定例
static datetime lastBarTime = 0;
if(Time[0] != lastBarTime)
{
    lastBarTime = Time[0];
    // ここでiCustomを呼び出す
    double signal = iCustom(NULL, 0, "MyIndicator", 0, 1);
}
</code></pre>
<h3><span id="toc22">5. バッファ番号は0〜7の範囲</span></h3>
<p>MT4ではインジケーターバッファのインデックスは<strong>0〜7</strong>の8個までです。バッファが8個を超えるインジケーターの場合、すべての値をiCustomで取得できるとは限りません。</p>
<h2><span id="toc23">まとめ</span></h2>
<p>iCustom関数は、カスタムインジケーターのシグナルをEAに組み込むための必須関数です。この記事のポイントをまとめます。</p>
<ul>
<li><strong>iCustom関数</strong>を使えば、Indicatorsフォルダにあるカスタムインジケーターの値をEAから取得できる</li>
<li>パラメーターは「通貨ペア → 時間足 → インジケーター名 → <strong>入力パラメーター</strong> → バッファ番号 → バー位置」の順に指定する</li>
<li><strong>バッファ番号</strong>の確認は、データウィンドウやソースコードから行う</li>
<li>矢印シグナル系のインジケーターは <code>EMPTY_VALUE</code> との比較でシグナル判定する</li>
<li><strong>バッファレスインジケーター</strong>（バッファを使わずオブジェクトで描画するもの）には使えない</li>
<li>パフォーマンスのため、新しいバー確定時にのみ呼び出す工夫をすると良い</li>
</ul>
<p>まずは簡単なインジケーターから試して、iCustom関数の使い方に慣れていきましょう。シグナルインジケーターをEA化できるようになれば、自動売買の幅が大きく広がりますよ！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13043/%e3%80%90mql4%e3%80%91icustom%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%a0%e3%82%a4%e3%83%b3%e3%82%b8/">【MQL4】iCustom関数の使い方を徹底解説！カスタムインジケーターをEAから呼び出す方法とサンプルコード</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【MQL4】iWPR関数の使い方を徹底解説！ウィリアムズ%Rでエントリーシグナルを作ろう</title>
		<link>https://mql-programing.com/archives/13040/%e3%80%90mql4%e3%80%91iwpr%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%a6%e3%82%a3%e3%83%aa%e3%82%a2%e3%83%a0%e3%82%bar%e3%81%a7/</link>
		
		<dc:creator><![CDATA[朝日奈りさ]]></dc:creator>
		<pubDate>Wed, 15 Apr 2026 01:00:00 +0000</pubDate>
				<category><![CDATA[【中級編】MQLプログラムの読み方・書き方]]></category>
		<category><![CDATA[注文関係]]></category>
		<category><![CDATA[MQL4]]></category>
		<category><![CDATA[EA開発]]></category>
		<category><![CDATA[テクニカルインジケーター]]></category>
		<category><![CDATA[iWPR]]></category>
		<category><![CDATA[ウィリアムズ%R]]></category>
		<guid isPermaLink="false">https://mql-programing.com/?p=13040</guid>

					<description><![CDATA[<p>「ウィリアムズ%R（Williams&#8217; Percent Range）」というインジケーターをご存知ですか？これはラリー・ウィリアムズ氏が考案したオシレーター系テクニカル指標で、相場の「買われすぎ」「売られすぎ [&#8230;]</p>
<p>投稿 <a href="https://mql-programing.com/archives/13040/%e3%80%90mql4%e3%80%91iwpr%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%a6%e3%82%a3%e3%83%aa%e3%82%a2%e3%83%a0%e3%82%bar%e3%81%a7/">【MQL4】iWPR関数の使い方を徹底解説！ウィリアムズ%Rでエントリーシグナルを作ろう</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></description>
										<content:encoded><![CDATA[<p>「ウィリアムズ%R（Williams&#8217; Percent Range）」というインジケーターをご存知ですか？これはラリー・ウィリアムズ氏が考案した<strong>オシレーター系テクニカル指標</strong>で、相場の「買われすぎ」「売られすぎ」を判断するのにとても便利なツールです。</p>
<p>MQL4では<strong>iWPR関数</strong>を使うことで、このウィリアムズ%Rの値を簡単に取得できます。この記事では、iWPR関数の基本的な使い方から、実践的なEA（自動売買）への応用まで、段階的にわかりやすく解説していきます。</p>
<h2><span id="toc1">ウィリアムズ%Rとは？</span></h2>
<p>ウィリアムズ%Rは、一定期間における最高値と最安値の範囲のなかで、現在の終値がどの位置にあるかをパーセンテージで示す指標です。</p>
<h3><span id="toc2">計算式</span></h3>
<p>ウィリアムズ%Rの計算式は以下のとおりです。</p>
<pre><code class="language-mql4">// ウィリアムズ%Rの計算式（概念）
// %R = (期間内の最高値 - 現在の終値) / (期間内の最高値 - 期間内の最安値) × (-100)
</code></pre>
<p>この計算により、値は常に<strong>0 ～ -100</strong>の範囲で推移します。ここが他のオシレーターと少し違うポイントで、値がマイナスの範囲で動くことを覚えておきましょう。</p>
<h3><span id="toc3">値の見方</span></h3>
<ul>
<li><strong>0 に近い（-20より上）</strong>：買われすぎゾーン → 売りシグナルの候補</li>
<li><strong>-100 に近い（-80より下）</strong>：売られすぎゾーン → 買いシグナルの候補</li>
<li><strong>-50 付近</strong>：中立的な状態</li>
</ul>
<p>ストキャスティクスと非常に似た性質を持っていますが、ウィリアムズ%Rはスケールが反転している点が特徴です。ストキャスティクスでは値が高いほど買われすぎですが、ウィリアムズ%Rでは値が0に近いほど買われすぎとなります。</p>
<h2><span id="toc4">iWPR関数の構文</span></h2>
<p>MQL4でウィリアムズ%Rの値を取得するには、<strong>iWPR関数</strong>を使います。構文は以下のとおりです。</p>
<pre><code class="language-mql4">double iWPR(
    string symbol,      // 通貨ペア名
    int    timeframe,   // 時間足
    int    period,      // 計算期間
    int    shift        // シフト（何本前のバーか）
);
</code></pre>
<h3><span id="toc5">引数の詳細</span></h3>
<table>
<thead>
<tr>
<th>引数</th>
<th>型</th>
<th>説明</th>
<th>例</th>
</tr>
</thead>
<tbody>
<tr>
<td>symbol</td>
<td>string</td>
<td>通貨ペア名。NULLで現在のチャート</td>
<td>NULL, &#8220;USDJPY&#8221;</td>
</tr>
<tr>
<td>timeframe</td>
<td>int</td>
<td>時間足の定数。0で現在の時間足</td>
<td>0, PERIOD_H1</td>
</tr>
<tr>
<td>period</td>
<td>int</td>
<td>計算に使うバーの本数</td>
<td>14</td>
</tr>
<tr>
<td>shift</td>
<td>int</td>
<td>取得するバーの位置（0が最新）</td>
<td>0, 1</td>
</tr>
</tbody>
</table>
<p><strong>戻り値</strong>はdouble型で、0 ～ -100 の範囲の値が返されます。</p>
<h2><span id="toc6">基本的な使い方</span></h2>
<p>まずは、iWPR関数で値を取得してログに出力するシンプルな例を見てみましょう。</p>
<pre><code class="language-mql4">void OnTick()
{
    // 現在のチャート、現在の時間足、期間14、1本前の確定バーのウィリアムズ%Rを取得
    double wpr = iWPR(NULL, 0, 14, 1);

    // エキスパートログに出力
    Print("Williams %%R (1本前) = ", DoubleToString(wpr, 2));

    // 買われすぎ・売られすぎの判定
    if(wpr > -20)
    {
        Print("→ 買われすぎゾーン");
    }
    else if(wpr < -80)
    {
        Print("→ 売られすぎゾーン");
    }
    else
    {
        Print("→ 中立ゾーン");
    }
}
</code></pre>
<p>ここで<strong>shift に 1 を指定</strong>している点がポイントです。shift=0 だと現在まだ形成中のバーの値を取得してしまい、リアルタイムで値が変動します。EA開発では、確定したバー（shift=1）の値を使うのが基本です。</p>
<h2><span id="toc7">サンプル①：買われすぎ・売られすぎの状態をチャートに表示する</span></h2>
<p>次に、ウィリアムズ%Rの状態をチャートのコメントとしてリアルタイム表示するコードを作ってみましょう。</p>
<pre><code class="language-mql4">// ウィリアムズ%Rの状態表示スクリプト
extern int WPR_Period = 14;          // 計算期間
extern double OverBought = -20.0;    // 買われすぎライン
extern double OverSold   = -80.0;    // 売られすぎライン

void OnTick()
{
    double wprCurrent = iWPR(NULL, 0, WPR_Period, 0);
    double wprPrev    = iWPR(NULL, 0, WPR_Period, 1);

    string status = "";

    if(wprPrev > OverBought)
        status = "★ 買われすぎゾーン（売りに注目）";
    else if(wprPrev < OverSold)
        status = "★ 売られすぎゾーン（買いに注目）";
    else
        status = "― 中立ゾーン";

    Comment(
        "===== Williams %R Monitor =====\n",
        "期間: ", WPR_Period, "\n",
        "現在値 (形成中): ", DoubleToString(wprCurrent, 2), "\n",
        "確定値 (1本前) : ", DoubleToString(wprPrev, 2), "\n",
        "状態: ", status, "\n",
        "================================"
    );
}
</code></pre>
<p>このコードをEAとしてチャートにセットすると、左上にウィリアムズ%Rの値と状態がリアルタイムで表示されます。動きを観察しながら指標の特性を学ぶのに最適です。</p>
<h2><span id="toc8">サンプル②：ゾーン脱出型シグナルのシンプルEA</span></h2>
<p>ウィリアムズ%Rを使ったEAを作る際、単純に「-80以下で買い」とするとダマシが多くなります。そこで、<strong>ゾーン脱出型</strong>の考え方を取り入れます。</p>
<p>ゾーン脱出型とは、以下のようなロジックです。</p>
<ul>
<li><strong>買いシグナル</strong>：売られすぎゾーン（-80以下）に入った後、-80を上回って脱出したとき</li>
<li><strong>売りシグナル</strong>：買われすぎゾーン（-20以上）に入った後、-20を下回って脱出したとき</li>
</ul>
<p>これにより、ゾーン内に張り付いたまま反転しないケースのダマシを軽減できます。</p>
<pre><code class="language-mql4">// ゾーン脱出型 ウィリアムズ%R EA
extern int    WPR_Period  = 14;
extern double LotSize     = 0.01;
extern double OverBought  = -20.0;
extern double OverSold    = -80.0;
extern int    StopLoss    = 100;     // ストップロス（pips）
extern int    TakeProfit  = 200;     // テイクプロフィット（pips）
extern int    MagicNumber = 12345;

void OnTick()
{
    // 新しいバーが確定したときだけ処理する
    static datetime lastBarTime = 0;
    if(Time[0] == lastBarTime) return;
    lastBarTime = Time[0];

    // 確定バーと、その1つ前のバーのウィリアムズ%Rを取得
    double wpr1 = iWPR(NULL, 0, WPR_Period, 1);  // 直近の確定バー
    double wpr2 = iWPR(NULL, 0, WPR_Period, 2);  // その1つ前

    // 既存ポジションの確認
    int posCount = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
                posCount++;
        }
    }

    // ポジションがない場合のみエントリー判定
    if(posCount > 0) return;

    double sl, tp;

    // 買いシグナル：売られすぎゾーンから脱出
    if(wpr2 < OverSold &#038;&#038; wpr1 >= OverSold)
    {
        sl = Ask - StopLoss * Point * 10;
        tp = Ask + TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
                               "WPR Buy Signal", MagicNumber, 0, clrBlue);
        if(ticket > 0)
            Print("買いエントリー: WPR=", DoubleToString(wpr1, 2));
        else
            Print("買い注文エラー: ", GetLastError());
    }

    // 売りシグナル：買われすぎゾーンから脱出
    if(wpr2 > OverBought && wpr1 <= OverBought)
    {
        sl = Bid + StopLoss * Point * 10;
        tp = Bid - TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
                               "WPR Sell Signal", MagicNumber, 0, clrRed);
        if(ticket > 0)
            Print("売りエントリー: WPR=", DoubleToString(wpr1, 2));
        else
            Print("売り注文エラー: ", GetLastError());
    }
}
</code></pre>
<p>このEAのポイントは以下のとおりです。</p>
<ul>
<li><strong>新しいバー確定時のみ判定</strong>：static変数でバーの時刻を管理し、同じバーで何度も判定しない</li>
<li><strong>ゾーン脱出の判定</strong>：2本前がゾーン内、1本前がゾーン外になったことで「脱出」を検知</li>
<li><strong>ポジション制限</strong>：同時に1ポジションのみ持つようにしている</li>
</ul>
<h2><span id="toc9">サンプル③：移動平均線との組み合わせ（トレンドフィルター付きEA）</span></h2>
<p>オシレーター系指標の弱点は、<strong>強いトレンドが発生している局面</strong>では買われすぎ・売られすぎの状態が長く続き、シグナルが機能しにくいことです。</p>
<p>これを改善するために、<strong>移動平均線によるトレンドフィルター</strong>を追加したEAを作ってみましょう。</p>
<pre><code class="language-mql4">// トレンドフィルター付き ウィリアムズ%R EA
extern int    WPR_Period  = 14;
extern int    MA_Period   = 50;      // 移動平均線の期間
extern int    MA_Method   = MODE_SMA; // 移動平均の種類
extern double LotSize     = 0.01;
extern double OverBought  = -20.0;
extern double OverSold    = -80.0;
extern int    StopLoss    = 100;
extern int    TakeProfit  = 200;
extern int    MagicNumber = 12346;

void OnTick()
{
    // 新しいバー確定時のみ処理
    static datetime lastBarTime = 0;
    if(Time[0] == lastBarTime) return;
    lastBarTime = Time[0];

    // ウィリアムズ%Rの値を取得
    double wpr1 = iWPR(NULL, 0, WPR_Period, 1);
    double wpr2 = iWPR(NULL, 0, WPR_Period, 2);

    // 移動平均線の値を取得
    double ma1 = iMA(NULL, 0, MA_Period, 0, MA_Method, PRICE_CLOSE, 1);

    // 現在の価格と移動平均線の位置関係でトレンドを判定
    double closePrice = Close[1];
    bool isUpTrend   = (closePrice > ma1);  // 上昇トレンド
    bool isDownTrend = (closePrice < ma1);  // 下降トレンド

    // 既存ポジションの確認
    int posCount = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
                posCount++;
        }
    }

    if(posCount > 0) return;

    double sl, tp;

    // 買いシグナル：上昇トレンド中 + 売られすぎゾーンから脱出
    if(isUpTrend && wpr2 < OverSold &#038;&#038; wpr1 >= OverSold)
    {
        sl = Ask - StopLoss * Point * 10;
        tp = Ask + TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
                               "WPR+MA Buy", MagicNumber, 0, clrBlue);
        if(ticket > 0)
            Print("買いエントリー（トレンドフィルター付き）: WPR=",
                  DoubleToString(wpr1, 2), " MA=", DoubleToString(ma1, 5));
    }

    // 売りシグナル：下降トレンド中 + 買われすぎゾーンから脱出
    if(isDownTrend && wpr2 > OverBought && wpr1 <= OverBought)
    {
        sl = Bid + StopLoss * Point * 10;
        tp = Bid - TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
                               "WPR+MA Sell", MagicNumber, 0, clrRed);
        if(ticket > 0)
            Print("売りエントリー（トレンドフィルター付き）: WPR=",
                  DoubleToString(wpr1, 2), " MA=", DoubleToString(ma1, 5));
    }
}
</code></pre>
<p>このEAでは、以下のフィルタリングを行っています。</p>
<ul>
<li><strong>買いエントリー</strong>：価格が移動平均線より上（上昇トレンド）のときだけ、売られすぎからの脱出シグナルを採用</li>
<li><strong>売りエントリー</strong>：価格が移動平均線より下（下降トレンド）のときだけ、買われすぎからの脱出シグナルを採用</li>
</ul>
<p>こうすることで、<strong>トレンド方向と逆行するエントリーを防ぎ</strong>、勝率の向上が期待できます。</p>
<h2><span id="toc10">iWPR関数を使う際の注意点</span></h2>
<h3><span id="toc11">1. 値の範囲はマイナスである</span></h3>
<p>ウィリアムズ%Rの値は<strong>0 ～ -100</strong>です。RSIのように0～100ではないので、条件式を書くときに符号を間違えないよう注意してください。例えば「-80以下」は <code>wpr &lt; -80</code> と書きます。</p>
<h3><span id="toc12">2. トレーディングスタイルに合わせた期間設定</span></h3>
<p>ウィリアムズ%Rの計算期間は、トレーディングスタイルに合わせて調整するのがおすすめです。</p>
<table>
<thead>
<tr>
<th>スタイル</th>
<th>推奨期間</th>
<th>特徴</th>
</tr>
</thead>
<tbody>
<tr>
<td>スキャルピング</td>
<td>7</td>
<td>シグナルが敏感、ダマシも多い</td>
</tr>
<tr>
<td>デイトレード</td>
<td>14</td>
<td>バランスが良い（デフォルト）</td>
</tr>
<tr>
<td>スイングトレード</td>
<td>21〜28</td>
<td>シグナルは少ないが信頼性が高い</td>
</tr>
</tbody>
</table>
<h3><span id="toc13">3. 強いトレンド相場には注意</span></h3>
<p>オシレーター系指標全般に言えることですが、強い上昇トレンドや下降トレンドでは、ウィリアムズ%Rが買われすぎ・売られすぎゾーンに張り付いたまま動かないことがあります。このような場合、逆張りシグナルが機能しません。サンプル③のように<strong>トレンドフィルターと組み合わせる</strong>ことを強くおすすめします。</p>
<h3><span id="toc14">4. 確定バーの値を使う</span></h3>
<p>EA開発では、形成中のバー（shift=0）ではなく、<strong>確定したバー（shift=1以上）の値を使う</strong>のが鉄則です。形成中のバーの値はティックごとに変動するため、シグナルがチラつく原因になります。</p>
<h2><span id="toc15">まとめ</span></h2>
<p>この記事では、MQL4のiWPR関数を使ってウィリアムズ%Rの値を取得し、EA開発に活用する方法を解説しました。最後にポイントをおさらいしましょう。</p>
<ul>
<li><strong>iWPR関数</strong>は4つの引数（symbol, timeframe, period, shift）を指定してウィリアムズ%Rの値を取得する</li>
<li>値の範囲は<strong>0 ～ -100</strong>で、-20以上が買われすぎ、-80以下が売られすぎ</li>
<li><strong>ゾーン脱出型</strong>のシグナルにすることで、単純なゾーン判定よりダマシを軽減できる</li>
<li><strong>移動平均線などのトレンドフィルター</strong>と組み合わせることで、さらに精度を高められる</li>
<li>EA開発では必ず<strong>確定バー（shift=1）</strong>の値を使うこと</li>
</ul>
<p>ウィリアムズ%Rはシンプルな指標ですが、正しく使えばエントリーポイントの精度を上げる強力な武器になります。まずはサンプルコードをストラテジーテスターで動かして、動作を確認するところから始めてみてください！</p>
<p>投稿 <a href="https://mql-programing.com/archives/13040/%e3%80%90mql4%e3%80%91iwpr%e9%96%a2%e6%95%b0%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e3%82%92%e5%be%b9%e5%ba%95%e8%a7%a3%e8%aa%ac%ef%bc%81%e3%82%a6%e3%82%a3%e3%83%aa%e3%82%a2%e3%83%a0%e3%82%bar%e3%81%a7/">【MQL4】iWPR関数の使い方を徹底解説！ウィリアムズ%Rでエントリーシグナルを作ろう</a> は <a href="https://mql-programing.com">自動売買を作ろう！</a> に最初に表示されました。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
