
プログラムで保有ポジション数を取得するには、OrdersTotal関数を使うよ!
OrdersTotal関数とは
自動売買でトレードするとき、保有ポジション数をチェックしたいですよね!
そのときに OrdersTotal関数を使いましょう。
OrdersTotal関数とは、保有ポジションの数を返します。
例えば、ポジション数が2つなら、OrdersTotal関数は2を返します。
返り値は保有ポジション数で、引数は何も必要ありません。
返り値は int型なので、基本的な書き方は以下の通りです。
int positionNum = OrdersTotal();
上記のプログラムを書くことで、positionNum に保有ポジション数が代入されます。
OrdersTotal関数の使用方法と注意点
OrdersTotal関数は、保有ポジション数を返します。
そのため、ポジションの情報をチェックするための for文でよく使われます。
具体的には以下の通りです。
//保有ポジションをチェック
for(int i = OrdersTotal() - 1; i >= 0; i--){
//ここにポジションビの情報を1つ1つチェックするためのプログラムを書く
}
ここでのポイントは OrdersTotal関数ではなく、「i–」の部分です。
for文を「i++」で書くこともできるのですが、「i++」だとエラーが起こる可能性があります。
「i++」で書いた例がこちらです。
//エラーが起こる可能性がある例
for(int i = 0; i <= OrdersTotal()-1; i++){
//ここにポジションの情報を1つ1つチェックするためのプログラムを書く
}
なぜエラーが起こる可能性があるのかというと、for文の中で配列を使っている場合、存在しない配列を参照してしまうからです。
例えば、hairetsu[3] という配列を使っている場合、for文なので hairetsu[i] と書いていると思います。
そのとき、i は「0→1→2」という順に変化します。
そして、for文が途中の「0→1」の段階でポジションが決済された場合を考えます。
ポジションが決済された場合、「2」で参照されるはずだった hairetsu[2] が存在しないものになっているので、エラーが出ます。
そのため、「2→1→0」の順番で参照したほうが、エラーが出ないので、トラブルがなくなるでしょう。
配列をマスターしていない方は、こちらの記事が参考になります。
OrdersTotal関数の実用的なプログラム例
ここからは、OrdersTotal関数を実際のEAでどのように活用するか、具体的なプログラム例を紹介します。
例1:最大ポジション数を制限して新規注文を出すEA
EAを作るとき、「同時に保有するポジションを○個までに制限したい」という場面は非常に多いです。OrdersTotal関数を使えば、現在のポジション数を確認してから注文を出すことができます。
// --- 入力パラメータ ---
input int MaxPositions = 3; // 最大保有ポジション数
input double LotSize = 0.1; // 注文ロット数
input int MagicNumber = 12345; // マジックナンバー
void OnTick()
{
// 現在の自分のEAが保有しているポジション数をカウント
int myPositions = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
// ポジション情報を選択
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// マジックナンバーと通貨ペアが一致するものだけカウント
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
myPositions++;
}
}
}
// 最大ポジション数に達していなければ新規注文
if(myPositions < MaxPositions)
{
// 例:簡単な買い条件(移動平均のゴールデンクロス)
double maFast = iMA(Symbol(), 0, 5, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 1);
double maFastPrev = iMA(Symbol(), 0, 5, 0, MODE_SMA, PRICE_CLOSE, 2);
double maSlowPrev = iMA(Symbol(), 0, 25, 0, MODE_SMA, PRICE_CLOSE, 2);
// ゴールデンクロスが発生したら買い注文
if(maFastPrev < maSlowPrev && maFast > maSlow)
{
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, 0, 0,
"MaxPos制限EA", MagicNumber, 0, clrBlue);
if(ticket < 0)
Print("注文エラー: ", GetLastError());
else
Print("買い注文成功! チケット番号: ", ticket);
}
}
else
{
// 最大ポジション数に達している場合は何もしない
// Print("最大ポジション数に達しています: ", myPositions, " / ", MaxPositions);
}
}ポイントは、OrdersTotal関数でループしながらマジックナンバーと通貨ペアでフィルタリングしている点です。他のEAのポジションを誤ってカウントしないようにしましょう。
例2:保有中の全ポジションを一括決済する関数
特定の条件(例えば、合計利益が目標額に達した場合など)で、保有ポジションをすべて決済したいことがあります。以下は、自分のEAのポジションだけを一括で決済する関数です。
input int MagicNumber = 12345; // マジックナンバー
//+------------------------------------------------------------------+
//| 自分のEAの全ポジションを一括決済する関数 |
//+------------------------------------------------------------------+
void CloseAllMyPositions()
{
// OrdersTotal()を使って全ポジションを逆順にチェック
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
// ポジション情報を選択
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
continue; // 選択に失敗したらスキップ
// マジックナンバーと通貨ペアが一致するかチェック
if(OrderMagicNumber() != MagicNumber)
continue; // 違うEAのポジションはスキップ
if(OrderSymbol() != Symbol())
continue; // 違う通貨ペアのポジションはスキップ
bool result = false;
// 買いポジションの場合
if(OrderType() == OP_BUY)
{
result = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed);
}
// 売りポジションの場合
else if(OrderType() == OP_SELL)
{
result = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrBlue);
}
// 決済結果をログに出力
if(result)
Print("決済成功: チケット番号 ", OrderTicket());
else
Print("決済失敗: チケット番号 ", OrderTicket(), " エラー: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| OnTick関数での使用例 |
//+------------------------------------------------------------------+
void OnTick()
{
// 例:保有ポジションの合計利益が1万円を超えたら全決済
double totalProfit = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
// 各ポジションの損益を合算
totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
}
}
}
// 合計利益が目標に達したら全ポジション決済
if(totalProfit >= 10000)
{
Print("目標利益達成!合計利益: ", totalProfit, " 円 → 全決済実行");
CloseAllMyPositions();
}
}逆順(i--)でループしているのが重要です。決済するとポジション数が減るので、順方向でループするとインデックスがずれてしまいます。
例3:ポジション数をチャート上に表示するインジケーター
インジケーターとしてOrdersTotal関数を使い、現在の保有ポジション数や合計損益をチャート上にリアルタイム表示する例です。裁量トレードの補助ツールとしても便利です。
#property indicator_chart_window // チャートウィンドウに表示
#property strict
//+------------------------------------------------------------------+
//| 初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 終了時にオブジェクトを削除 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectDelete("PosInfoLabel"); // ラベルオブジェクトを削除
}
//+------------------------------------------------------------------+
//| ティックごとに情報を更新 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
// 全ポジション数を取得
int totalPositions = OrdersTotal();
// 現在の通貨ペアのポジションだけをカウント&損益を合算
int symbolPositions = 0;
double symbolProfit = 0;
int buyCount = 0; // 買いポジション数
int sellCount = 0; // 売りポジション数
for(int i = totalPositions - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol())
{
symbolPositions++;
symbolProfit += OrderProfit() + OrderSwap() + OrderCommission();
// 買い・売りを別々にカウント
if(OrderType() == OP_BUY) buyCount++;
if(OrderType() == OP_SELL) sellCount++;
}
}
}
// 表示用のテキストを作成
string displayText = StringFormat(
"全ポジション: %d | %s: %d (買:%d / 売:%d) | 損益: %.0f円",
totalPositions, Symbol(), symbolPositions, buyCount, sellCount, symbolProfit
);
// チャート上にラベルとして表示
if(ObjectFind("PosInfoLabel") < 0)
{
// オブジェクトが存在しなければ新規作成
ObjectCreate("PosInfoLabel", OBJ_LABEL, 0, 0, 0);
ObjectSet("PosInfoLabel", OBJPROP_CORNER, 0); // 左上に配置
ObjectSet("PosInfoLabel", OBJPROP_XDISTANCE, 10);
ObjectSet("PosInfoLabel", OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0, "PosInfoLabel", OBJPROP_FONTSIZE, 11);
}
// テキストと色を更新(利益ならブルー、損失ならレッド)
ObjectSetText("PosInfoLabel", displayText, 11, "Arial",
symbolProfit >= 0 ? clrDodgerBlue : clrRed);
return(rates_total);
}このインジケーターをチャートに適用すると、左上に「全ポジション数」「現在の通貨ペアのポジション数(買い/売り内訳)」「損益」がリアルタイムで表示されます。
例4:ポジションがゼロのときだけ新規エントリーするシンプルEA
初心者の方がEAを作るとき、まずは「1ポジションだけ保有する」シンプルな設計から始めるのがおすすめです。OrdersTotal関数を使えば、ポジションがゼロかどうかの判定が簡単にできます。
input double LotSize = 0.1; // 注文ロット数
input int StopLoss = 100; // ストップロス(ポイント)
input int TakeProfit = 200; // テイクプロフィット(ポイント)
input int MagicNumber = 99999; // マジックナンバー
//+------------------------------------------------------------------+
//| 自分のEAのポジション数を取得する関数 |
//+------------------------------------------------------------------+
int CountMyPositions()
{
int count = 0;
// OrdersTotal()で全ポジションをチェック
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// 自分のEA(マジックナンバー一致)かつ同じ通貨ペアのみカウント
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| OnTick関数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 自分のEAのポジションが0のときだけエントリーを判断
if(CountMyPositions() > 0)
return; // すでにポジションがあれば何もしない
// RSIを使ったシンプルな売買判断
double rsi = iRSI(Symbol(), 0, 14, PRICE_CLOSE, 1);
double sl, tp;
// RSIが30以下 → 売られすぎなので買いエントリー
if(rsi < 30)
{
sl = Ask - StopLoss * Point; // ストップロス価格を計算
tp = Ask + TakeProfit * Point; // テイクプロフィット価格を計算
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3,
sl, tp, "RSI買いエントリー", MagicNumber, 0, clrBlue);
if(ticket > 0)
Print("RSI=", rsi, " → 買いエントリー成功");
}
// RSIが70以上 → 買われすぎなので売りエントリー
else if(rsi > 70)
{
sl = Bid + StopLoss * Point; // ストップロス価格を計算
tp = Bid - TakeProfit * Point; // テイクプロフィット価格を計算
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3,
sl, tp, "RSI売りエントリー", MagicNumber, 0, clrRed);
if(ticket > 0)
Print("RSI=", rsi, " → 売りエントリー成功");
}
}CountMyPositions関数を作って、ポジション数のカウント処理を分離しているのがポイントです。こうすることで、OnTick内のコードがすっきりして読みやすくなります。EAが複雑になっても、この関数を使い回せるので便利です。
まとめ
OrdersTotal関数は、EAでとてもよく使う関数です。
自動売買がポジションを決済するときに使うなど、使用場面はたくさんあります。
そのため、ほとんどのEAで使われています。
注意点は、配列と組み合わせて使う場合、存在しない配列を参照してしまうことがあることです。
for文の順番をしっかりと考えて、OrdersTotal関数を使っていきましょう。





