MQL5 取引関数 完全ガイド|OrderSend・CTrade・ポジション管理・ロット計算

MQL5の取引関数を体系的にまとめました。OrderSendの構造体からCTradeクラス、ポジション管理、待機注文、SL/TP変更、トレーリングストップ、ロット計算、マジックナンバー、部分決済、取引履歴、OnTradeTransactionまで、EA開発に必要な取引処理のすべてをコード付きで解説します。

目次

MQL5の取引モデル(MQL4との根本的な違い)

MQL4とMQL5では取引の仕組みが根本的に異なります。MQL4は「注文=ポジション」でしたが、MQL5は「注文→約定→ポジション」の3段階モデルです。

概念MQL4MQL5
発注OrderSend()で直接注文OrderSend()でリクエスト送信
結果チケット番号が返るMqlTradeResult構造体で受け取る
ポジション管理OrderSelect(ticket)PositionSelectByTicket(ticket)
決済OrderClose(ticket)反対売買で決済(CTrade.PositionClose)
ヘッジング標準対応口座設定による(ネッティング/ヘッジ)
OrderSendの引数約10個の引数を直接渡すMqlTradeRequest構造体にセットして渡す

MQL5にはOrderClose()OrderModify()は存在しません。MQL4のコードをそのまま使うとコンパイルエラーになります。

MQL5の取引は、すべてOrderSend()関数にMqlTradeRequest構造体を渡して行います。成行注文も、指値注文も、SL/TP変更も、決済もすべてこの1つの関数で処理します。

OrderSend(MqlTradeRequest / MqlTradeResult 詳解)

MQL5の取引はすべてOrderSend()を通じて行います。2つの構造体を使います。

MqlTradeRequest — 注文リクエスト

取引サーバーに送る注文内容を格納する構造体です。actionフィールドの値によって、他に必要なフィールドが変わります。

フィールド説明
actionENUM_TRADE_REQUEST_ACTIONS取引操作の種類(TRADE_ACTION_DEAL / PENDING / SLTP / MODIFY / REMOVE)
magiculongEA識別用マジックナンバー
orderulong注文チケット(変更・削除時)
symbolstring通貨ペア
volumedoubleロット数
pricedouble価格
stoplimitdoubleストップリミット注文の指値
sldoubleストップロス
tpdoubleテイクプロフィット
deviationulong許容スリッページ(ポイント)
typeENUM_ORDER_TYPE注文タイプ(BUY / SELL / BUY_LIMIT等)
type_fillingENUM_ORDER_TYPE_FILLING充填タイプ(FOK / IOC / RETURN)
type_timeENUM_ORDER_TYPE_TIME有効期限タイプ(GTC / DAY / SPECIFIED等)
expirationdatetime有効期限日時
commentstringコメント
positionulongポジションチケット(決済・変更時)
position_byulong反対ポジションのチケット(CLOSE_BY時)

MqlTradeResult — 注文結果

フィールド説明
retcodeuintリターンコード(10009=成功)
dealulong約定チケット
orderulong注文チケット
volumedouble約定ロット数
pricedouble約定価格
biddouble現在のBid
askdouble現在のAsk
commentstringサーバーからのコメント
request_iduintリクエストID

成行買い注文の基本コード

void BuyMarket(double lot, int slPoints, int tpPoints)
  {
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = lot;
   request.type         = ORDER_TYPE_BUY;
   request.price        = ask;
   request.sl           = NormalizeDouble(ask - slPoints * _Point, _Digits);
   request.tp           = NormalizeDouble(ask + tpPoints * _Point, _Digits);
   request.deviation    = 10;
   request.type_filling = ORDER_FILLING_FOK;
   request.magic        = 12345;
   request.comment      = "Buy Order";

   if(!OrderSend(request, result))
     {
      Print("OrderSend失敗: ", GetLastError());
      return;
     }

   if(result.retcode == TRADE_RETCODE_DONE)
      Print("買い注文成功: ticket=", result.order, " price=", result.price);
   else
      Print("買い注文失敗: retcode=", result.retcode, " ", result.comment);
  }
重要

MqlTradeRequest request = {}; のように必ずゼロ初期化してください。初期化しないとゴミデータが入り、予期しないエラーの原因になります。

CTradeクラス(Buy / Sell / BuyStop / SellLimit等)

CTradeはMQL5標準ライブラリに含まれるクラスで、OrderSend()の複雑な構造体操作をラップしてくれます。実務のEA開発ではCTradeを使うのが一般的です。

#include <Trade\Trade.mqh>

CTrade trade;

int OnInit()
  {
   trade.SetExpertMagicNumber(12345);  // マジックナンバー設定
   trade.SetDeviationInPoints(10);     // 許容スリッページ
   trade.SetTypeFilling(ORDER_FILLING_FOK);  // 充填タイプ
   return INIT_SUCCEEDED;
  }

成行注文

// 成行買い(SL/TPなし)
trade.Buy(0.1, _Symbol);

// 成行買い(SL/TP付き)
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl  = NormalizeDouble(ask - 500 * _Point, _Digits);
double tp  = NormalizeDouble(ask + 1000 * _Point, _Digits);
trade.Buy(0.1, _Symbol, ask, sl, tp, "Buy with SL/TP");

// 成行売り
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
sl  = NormalizeDouble(bid + 500 * _Point, _Digits);
tp  = NormalizeDouble(bid - 1000 * _Point, _Digits);
trade.Sell(0.1, _Symbol, bid, sl, tp, "Sell with SL/TP");

// 結果の確認
if(trade.ResultRetcode() == TRADE_RETCODE_DONE)
   Print("注文成功: ", trade.ResultOrder());
else
   Print("注文失敗: ", trade.ResultRetcode(), " ", trade.ResultComment());

ポジション決済

// チケット番号で決済
trade.PositionClose(ticket);

// 通貨ペア指定で決済(その銘柄の全ポジション)
trade.PositionClose(_Symbol);

// 決済スリッページを指定
trade.PositionClose(ticket, 20);  // 20ポイントまで許容

注文タイプ(成行・指値・逆指値・ストップリミット)

MQL5では6種類の注文タイプが使えます。MQL4の4種類から、ストップリミット注文が追加されています。

定数種類説明
ORDER_TYPE_BUY成行買い現在のAsk価格で即時買い
ORDER_TYPE_SELL成行売り現在のBid価格で即時売り
ORDER_TYPE_BUY_LIMIT買い指値現在価格より低い価格で買い待ち
ORDER_TYPE_SELL_LIMIT売り指値現在価格より高い価格で売り待ち
ORDER_TYPE_BUY_STOP買い逆指値現在価格より高い価格で買い待ち(ブレイクアウト)
ORDER_TYPE_SELL_STOP売り逆指値現在価格より低い価格で売り待ち(ブレイクアウト)
ORDER_TYPE_BUY_STOP_LIMIT買いストップリミット指定価格に達したら買い指値注文を発行
ORDER_TYPE_SELL_STOP_LIMIT売りストップリミット指定価格に達したら売り指値注文を発行
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

// 買い指値: 現在価格より100pips下で待つ
double buyLimitPrice = NormalizeDouble(ask - 1000 * _Point, _Digits);
trade.BuyLimit(0.1, buyLimitPrice, _Symbol, 0, 0, ORDER_TIME_GTC, 0, "BuyLimit");

// 売り指値: 現在価格より100pips上で待つ
double sellLimitPrice = NormalizeDouble(bid + 1000 * _Point, _Digits);
trade.SellLimit(0.1, sellLimitPrice, _Symbol, 0, 0, ORDER_TIME_GTC, 0, "SellLimit");

// 買い逆指値: 現在価格より50pips上で待つ(ブレイクアウト狙い)
double buyStopPrice = NormalizeDouble(ask + 500 * _Point, _Digits);
trade.BuyStop(0.1, buyStopPrice, _Symbol, 0, 0, ORDER_TIME_GTC, 0, "BuyStop");

// 売り逆指値: 現在価格より50pips下で待つ(ブレイクアウト狙い)
double sellStopPrice = NormalizeDouble(bid - 500 * _Point, _Digits);
trade.SellStop(0.1, sellStopPrice, _Symbol, 0, 0, ORDER_TIME_GTC, 0, "SellStop");

指値・逆指値注文の価格は、現在価格からSTOP_LEVELポイント以上離す必要があります。近すぎるとINVALID_STOPSエラー(10016)になります。

ポジション管理(Select / GetDouble / GetInteger / Total)

MQL5ではポジション情報の取得に専用のPosition関数群を使います。MQL4のOrderSelect()でポジション情報を取る方法とは完全に異なります。

全ポジションのループ

void PrintAllPositions()
  {
   int total = PositionsTotal();
   Print("ポジション数: ", total);

   for(int i = 0; i < total; i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;

      // PositionGetTicket()で選択状態になるので、そのまま情報を取得できる
      string symbol  = PositionGetString(POSITION_SYMBOL);
      long   type    = PositionGetInteger(POSITION_TYPE);    // 0=BUY, 1=SELL
      double volume  = PositionGetDouble(POSITION_VOLUME);
      double openPr  = PositionGetDouble(POSITION_PRICE_OPEN);
      double sl      = PositionGetDouble(POSITION_SL);
      double tp      = PositionGetDouble(POSITION_TP);
      double profit  = PositionGetDouble(POSITION_PROFIT);
      long   magic   = PositionGetInteger(POSITION_MAGIC);

      PrintFormat("#%I64u %s %s %.2f lot  Open=%.5f  SL=%.5f  TP=%.5f  PL=%.2f  Magic=%I64d",
                  ticket, symbol,
                  (type == POSITION_TYPE_BUY) ? "BUY" : "SELL",
                  volume, openPr, sl, tp, profit, magic);
     }
  }

特定のポジションを選択

// 方法1: インデックスで選択(PositionGetTicketが選択も兼ねる)
ulong ticket = PositionGetTicket(0);  // 0番目のポジションを選択

// 方法2: チケット番号で選択
if(PositionSelectByTicket(12345))
  {
   double profit = PositionGetDouble(POSITION_PROFIT);
  }

// 方法3: 通貨ペアで選択(ネッティング口座向け)
if(PositionSelect(_Symbol))
  {
   double volume = PositionGetDouble(POSITION_VOLUME);
  }

PositionSelect(symbol)はネッティング口座では問題なく動きますが、ヘッジング口座では同じ通貨ペアに複数ポジションがあると最初の1つしか選択できません。ヘッジング口座ではPositionGetTicket()でループしてください。

自分のEAのポジションだけを取得

int CountMyPositions(long magicNumber, string symbol = "")
  {
   int count = 0;
   for(int i = 0; i < PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;

      if(PositionGetInteger(POSITION_MAGIC) != magicNumber)
         continue;
      if(symbol != "" && PositionGetString(POSITION_SYMBOL) != symbol)
         continue;

      count++;
     }
   return count;
  }

待機注文の管理(OrderGet / OrdersTotal / OrderSelect)

MQL5では「ポジション」と「待機注文(Pending Order)」は別のデータです。ポジションはPositionsTotal()、待機注文はOrdersTotal()で取得します。

// 待機注文の一覧表示
void PrintPendingOrders()
  {
   int total = OrdersTotal();
   Print("待機注文数: ", total);

   for(int i = 0; i < total; i++)
     {
      ulong ticket = OrderGetTicket(i);
      if(ticket == 0) continue;

      string symbol = OrderGetString(ORDER_SYMBOL);
      long   type   = OrderGetInteger(ORDER_TYPE);
      double volume = OrderGetDouble(ORDER_VOLUME_CURRENT);
      double price  = OrderGetDouble(ORDER_PRICE_OPEN);

      PrintFormat("#%I64u %s type=%d vol=%.2f price=%.5f",
                  ticket, symbol, type, volume, price);
     }
  }

// 特定マジックナンバーの待機注文をすべて削除
void DeleteAllPendingOrders(long magicNumber)
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)  // 逆順ループ
     {
      ulong ticket = OrderGetTicket(i);
      if(ticket == 0) continue;

      if(OrderGetInteger(ORDER_MAGIC) == magicNumber)
         trade.OrderDelete(ticket);
     }
  }

待機注文を削除するループは逆順(i–)で回してください。順方向で回すと、削除のたびにインデックスがずれて注文がスキップされます。

SL/TPの設定と変更

既存ポジションのSL/TPを変更するにはTRADE_ACTION_SLTPを使います。CTradeクラスならPositionModify()一発です。

// CTradeでSL/TP変更
bool ModifySLTP(ulong ticket, double newSL, double newTP)
  {
   newSL = NormalizeDouble(newSL, _Digits);
   newTP = NormalizeDouble(newTP, _Digits);

   if(!trade.PositionModify(ticket, newSL, newTP))
     {
      Print("SL/TP変更失敗: ", trade.ResultRetcode(), " ", trade.ResultComment());
      return false;
     }
   return true;
  }

// OrderSend直接でSL/TP変更
void ModifySLTP_Direct(ulong ticket, double newSL, double newTP)
  {
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action   = TRADE_ACTION_SLTP;
   request.position = ticket;
   request.symbol   = _Symbol;
   request.sl       = NormalizeDouble(newSL, _Digits);
   request.tp       = NormalizeDouble(newTP, _Digits);

   if(!OrderSend(request, result))
      Print("SL/TP変更失敗: ", GetLastError());
   else if(result.retcode != TRADE_RETCODE_DONE)
      Print("SL/TP変更失敗: ", result.retcode);
  }

SL/TP変更時はaction = TRADE_ACTION_SLTPです。TRADE_ACTION_DEALではありません。間違えると新規注文が発注されてしまいます。

トレーリングストップの実装

トレーリングストップは、価格が有利な方向に動いたときにSLを追従させる仕組みです。MT5の標準機能にもありますが、EAに組み込むことで細かい制御ができます。

void TrailingStop(int trailPoints, int trailStepPoints, long magicNumber)
  {
   double trailDistance = trailPoints * _Point;
   double stepDistance  = trailStepPoints * _Point;

   for(int i = 0; i < PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;

      long   posType = PositionGetInteger(POSITION_TYPE);
      double openPr  = PositionGetDouble(POSITION_PRICE_OPEN);
      double currentSL = PositionGetDouble(POSITION_SL);
      double tp      = PositionGetDouble(POSITION_TP);

      if(posType == POSITION_TYPE_BUY)
        {
         double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

         // 価格がトレール開始距離以上に有利に動いている場合のみ
         if(bid - openPr < trailDistance) continue;

         double newSL = NormalizeDouble(bid - trailDistance, _Digits);

         // 新しいSLが現在のSLよりstep以上有利な場合のみ移動
         if(newSL > currentSL + stepDistance)
            trade.PositionModify(ticket, newSL, tp);
        }
      else if(posType == POSITION_TYPE_SELL)
        {
         double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

         if(openPr - ask < trailDistance) continue;

         double newSL = NormalizeDouble(ask + trailDistance, _Digits);

         if(currentSL == 0 || newSL < currentSL - stepDistance)
            trade.PositionModify(ticket, newSL, tp);
        }
     }
  }

// OnTick()から呼び出す例
void OnTick()
  {
   TrailingStop(300, 50, 12345);  // 30pipsのトレール、5pipsステップ
  }
  • trailPoints: 現在価格からSLまでの距離。相場がこの距離以上動いたらトレール開始
  • trailStepPoints: SLを移動する最小幅。細かすぎるとサーバーリクエストが多くなる
  • 売りポジションのcurrentSL == 0チェックは、SL未設定時の対策

ロット計算(リスクベース自動計算)

固定ロットではなく、口座残高の一定割合をリスクとしてロットを自動計算する方法です。プロのEAでは標準的に使われています。

// 口座残高の riskPercent% をリスクとしてロットを計算
// slPoints: SLまでの距離(ポイント単位)
double CalcLotByRisk(string symbol, double riskPercent, int slPoints)
  {
   if(slPoints <= 0) return 0.0;

   double balance   = AccountInfoDouble(ACCOUNT_BALANCE);
   double riskMoney = balance * riskPercent / 100.0;

   // 1ロット1ポイント動いたときの損益(ティック値)
   double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize  = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);

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

   double pointValue = tickValue / tickSize * _Point;
   double lot = riskMoney / (slPoints * pointValue);

   // ブローカーのロット制約に合わせる
   double minLot  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);

   lot = MathMax(minLot, lot);
   lot = MathMin(maxLot, lot);
   lot = MathFloor(lot / lotStep) * lotStep;

   return NormalizeDouble(lot, 2);
  }

// 使用例: 残高の2%リスク、SL 500ポイント(50pips)
double lot = CalcLotByRisk(_Symbol, 2.0, 500);
trade.Buy(lot, _Symbol);

クロス円(EURJPY等)と非クロス円(EURUSD等)ではTICK_VALUEが大きく異なります。必ずSymbolInfoDouble()から取得し、ハードコーディングしないでください。

マジックナンバー(複数EA管理)

マジックナンバーは、どのEAがどのポジション/注文を出したかを識別するための数値です。1つのMT5に複数のEAを動かす場合、これがないと他のEAのポジションを誤って決済してしまいます。

input long MagicNumber = 20240101;  // EA固有のマジックナンバー

int OnInit()
  {
   trade.SetExpertMagicNumber(MagicNumber);
   return INIT_SUCCEEDED;
  }

// ポジション操作時は必ずマジックナンバーでフィルタ
void CloseAllMyPositions()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;

      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;

      trade.PositionClose(ticket);
     }
  }
  • マジックナンバーはinputで宣言し、ユーザーが変更可能にする
  • 同じEAを複数チャートで動かす場合、異なるマジックナンバーを設定する
  • 手動注文のマジックナンバーは0。EAのマジックナンバーを0にすると手動注文と区別できない

部分決済

ポジションの一部だけを決済する方法です。例えば1.0ロットのうち0.5ロットだけ利確し、残りはトレールで伸ばす、といった使い方ができます。

// ポジションの半分を決済する
bool PartialClose(ulong ticket, double closeLot)
  {
   if(!PositionSelectByTicket(ticket))
     {
      Print("ポジションが見つかりません: ", ticket);
      return false;
     }

   string symbol = PositionGetString(POSITION_SYMBOL);
   long   type   = PositionGetInteger(POSITION_TYPE);
   double volume = PositionGetDouble(POSITION_VOLUME);

   // 決済ロットをロットステップに合わせる
   double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   closeLot = MathFloor(closeLot / lotStep) * lotStep;
   closeLot = MathMin(closeLot, volume);  // 保有数量を超えない

   if(closeLot <= 0) return false;

   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action   = TRADE_ACTION_DEAL;
   request.position = ticket;
   request.symbol   = symbol;
   request.volume   = closeLot;
   request.deviation = 10;
   request.type_filling = ORDER_FILLING_FOK;

   // 反対売買で決済
   if(type == POSITION_TYPE_BUY)
     {
      request.type  = ORDER_TYPE_SELL;
      request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
     }
   else
     {
      request.type  = ORDER_TYPE_BUY;
      request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
     }

   if(!OrderSend(request, result))
     {
      Print("部分決済失敗: ", GetLastError());
      return false;
     }

   if(result.retcode == TRADE_RETCODE_DONE)
     {
      Print("部分決済成功: ", closeLot, " lot closed");
      return true;
     }

   Print("部分決済失敗: ", result.retcode, " ", result.comment);
   return false;
  }

// 使用例: ポジションの半分を決済
if(PositionSelectByTicket(ticket))
  {
   double halfLot = PositionGetDouble(POSITION_VOLUME) / 2.0;
   PartialClose(ticket, halfLot);
  }

部分決済後にポジションのチケット番号が変わるブローカーがあります。部分決済後はポジション情報を再取得してください。

取引履歴(HistorySelect / HistoryDealGet)

過去の取引履歴を取得するには、まずHistorySelect()で期間を指定してから、HistoryDealsTotal()HistoryDealGetTicket()でループします。

// 今日の取引履歴を取得
void PrintTodayDeals(long magicNumber)
  {
   MqlDateTime today;
   TimeCurrent(today);
   today.hour = 0;
   today.min  = 0;
   today.sec  = 0;
   datetime startOfDay = StructToTime(today);

   // 履歴をロード
   if(!HistorySelect(startOfDay, TimeCurrent()))
     {
      Print("履歴取得失敗");
      return;
     }

   int totalDeals = HistoryDealsTotal();
   double totalProfit = 0;
   int    tradeCount  = 0;

   for(int i = 0; i < totalDeals; i++)
     {
      ulong dealTicket = HistoryDealGetTicket(i);
      if(dealTicket == 0) continue;

      // マジックナンバーでフィルタ
      if(HistoryDealGetInteger(dealTicket, DEAL_MAGIC) != magicNumber) continue;

      long dealEntry = HistoryDealGetInteger(dealTicket, DEAL_ENTRY);
      // DEAL_ENTRY_OUT = 決済約定のみカウント
      if(dealEntry != DEAL_ENTRY_OUT) continue;

      double profit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT);
      double commission = HistoryDealGetDouble(dealTicket, DEAL_COMMISSION);
      double swap = HistoryDealGetDouble(dealTicket, DEAL_SWAP);

      totalProfit += profit + commission + swap;
      tradeCount++;

      PrintFormat("Deal #%I64u  PL=%.2f  Commission=%.2f  Swap=%.2f",
                  dealTicket, profit, commission, swap);
     }

   PrintFormat("本日の取引: %d回  合計損益: %.2f", tradeCount, totalProfit);
  }
重要

HistorySelect()を呼ばないと履歴データが空の状態です。HistoryDealsTotal()やHistoryDealGetTicket()を使う前に必ず呼んでください。

直近の約定情報を取得

// 直近の決済約定の損益を取得
double GetLastClosedProfit(long magicNumber)
  {
   HistorySelect(0, TimeCurrent());

   for(int i = HistoryDealsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = HistoryDealGetTicket(i);
      if(ticket == 0) continue;

      if(HistoryDealGetInteger(ticket, DEAL_MAGIC) != magicNumber) continue;
      if(HistoryDealGetInteger(ticket, DEAL_ENTRY) != DEAL_ENTRY_OUT) continue;

      return HistoryDealGetDouble(ticket, DEAL_PROFIT)
           + HistoryDealGetDouble(ticket, DEAL_COMMISSION)
           + HistoryDealGetDouble(ticket, DEAL_SWAP);
     }

   return 0;
  }

OnTradeTransaction(取引イベント処理)

OnTradeTransaction()は取引に変化があったときに自動的に呼ばれるイベントハンドラです。ポジションが約定した瞬間、SL/TPが変更された瞬間などをリアルタイムで検知できます。

void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
   // 約定が完了したタイミングを検知
   if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
     {
      ulong dealTicket = trans.deal;

      // 履歴から約定情報を取得
      if(HistoryDealSelect(dealTicket))
        {
         long entry = HistoryDealGetInteger(dealTicket, DEAL_ENTRY);

         if(entry == DEAL_ENTRY_IN)
           {
            Print("新規ポジション約定: deal=", dealTicket,
                  " price=", HistoryDealGetDouble(dealTicket, DEAL_PRICE));
           }
         else if(entry == DEAL_ENTRY_OUT)
           {
            double profit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT);
            Print("決済約定: deal=", dealTicket, " 損益=", profit);
           }
        }
     }
  }

OnTradeTransaction()の主な用途:

  • 新規ポジション約定後に自動でSL/TPを設定
  • 決済後に次の注文を自動で発行
  • 部分決済の検知
  • 取引結果のログ記録

OnTradeTransaction()内での新規発注は注意が必要です。1回の取引で複数回呼ばれることがあるため、重複発注を防ぐロジックを入れてください。

TRADE_TRANSACTION_TYPE一覧

定数意味
TRADE_TRANSACTION_ORDER_ADD注文がサーバーに追加された
TRADE_TRANSACTION_ORDER_UPDATE注文が更新された
TRADE_TRANSACTION_ORDER_DELETE注文が削除された
TRADE_TRANSACTION_DEAL_ADD約定が履歴に追加された
TRADE_TRANSACTION_DEAL_UPDATE約定が更新された
TRADE_TRANSACTION_DEAL_DELETE約定が削除された
TRADE_TRANSACTION_HISTORY_ADD注文が履歴に追加された
TRADE_TRANSACTION_HISTORY_UPDATE履歴の注文が更新された
TRADE_TRANSACTION_HISTORY_DELETE履歴の注文が削除された
TRADE_TRANSACTION_POSITIONポジションが変更された(SL/TP等)
TRADE_TRANSACTION_REQUEST取引リクエストが処理された

プロが開発したEAをお探しの方は → シストレ.COM EA一覧

シストレ.COMで実績のあるEAが使い放題!/
無料会員登録はこちら
FX自動売買でEAを探すなら
シストレ.COM
実績あるEAが無料
厳格な審査を乗り越えた実績のあるEAが無料で使えます!
自由な口座選び
有料版を購入し柔軟な口座選びが可能!
フォワードテスト公開
全EAのフォワードテスト結果を公開中!
FX初心者も安心
初心者の方も安心して取引を始められます。
多様なEA選択肢
様々な種別のEAをご用意!自分の手法にあった取引が可能です。
信頼のFX会社と提携
人気のFX会社と提携中!様々なFX会社から選べます。
1分で登録完了!EA探すならシストレ.COM!/
無料会員登録はこちら
【FX自動売買】システムトレード完全ガイド|Forex Guide

この記事が気に入ったら
フォローしてね!

お役立ち情報をシェアする
  • URLをコピーしました!
目次