【MQL5】DatabaseTransactionCommit関数の使い方と自動売買実装コード

1. DatabaseTransactionCommit関数の概要と実務での活用法

MQL5に標準搭載されているSQLiteデータベース機能において、DatabaseTransactionCommitは、「開始したトランザクション(一連の処理)を確定させ、データベースに永続的に反映させる」ための非常に重要な関数です。

実務レベルのEA(エキスパートアドバイザー)開発では、バックテスト結果の保存や、数千行に及ぶティックデータの統計処理、あるいは複雑なトレードログの管理が必要になります。これらを1レコードずつ愚直に書き込んでいると、ストレージ(SSD/HDD)への書き込み回数が膨大になり、実行速度が著しく低下します。

ここで「トランザクション」を利用します。DatabaseTransactionBeginで処理を開始し、複数の書き込み(INSERTやUPDATE)を行った後、最後にこのDatabaseTransactionCommitを呼び出すことで、メモリ上の変更を一気にディスクへ書き込みます。 これにより、処理速度が数百倍から数千倍に向上するだけでなく、一連の処理が「全て成功するか、全く行われないか」というデータの整合性(原子性)を担保できるのです。

2. 構文と戻り値

DatabaseTransactionCommit関数の構成は非常にシンプルです。

bool DatabaseTransactionCommit(
   int  database      // DatabaseOpenで取得したデータベースハンドル
);

パラメーター

  • database: DatabaseOpen関数によって返された、操作対象のデータベースハンドル(整数値)を指定します。

戻り値

  • 成功時: true を返します。
  • 失敗時: false を返します。失敗の理由を確認するには、GetLastError()関数を呼び出します。

3. 具体的な使い方・実践サンプルコード

以下は、複数のトレード履歴をデータベースに高速に一括保存する実用的なスクリプトの例です。

void OnStart()
{
   string filename = "TradeLog.sqlite";
   // 1. データベースを開く(または作成)
   int db = DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE);

   if(db == INVALID_HANDLE) {
      Print("DBオープン失敗: ", GetLastError());
      return;
   }

   // テーブル作成(存在しない場合)
   DatabaseExecute(db, "CREATE TABLE IF NOT EXISTS TradeHistory(ID INTEGER PRIMARY KEY, Symbol TEXT, Profit REAL);");

   // --- トランザクション開始 ---
   // これにより、ループ内の書き込みがメモリ上にバッファリングされます
   if(!DatabaseTransactionBegin(db)) {
      Print("トランザクション開始失敗: ", GetLastError());
      DatabaseClose(db);
      return;
   }

   bool success = true;
   for(int i = 0; i < 1000; i++) {
      string query = StringFormat("INSERT INTO TradeHistory (Symbol, Profit) VALUES ('USDJPY', %f);", MathRand() / 100.0);

      if(!DatabaseExecute(db, query)) {
         Print("データ挿入失敗: ", GetLastError());
         success = false;
         break;
      }
   }

   // 2. 処理が全て成功したならコミット(確定)
   if(success) {
      if(DatabaseTransactionCommit(db)) {
         Print("1000件のデータを正常に一括保存しました。");
      } else {
         Print("コミット失敗: ", GetLastError());
      }
   } else {
      // 3. 途中でエラーがあればロールバック(破棄)して整合性を守る
      DatabaseTransactionRollback(db);
      Print("エラーが発生したため、変更を破棄しました。");
   }

   // データベースを閉じる
   DatabaseClose(db);
}

4. 使用上の注意点とよくあるエラー

  1. Commit忘れによるデータ消失:
    DatabaseTransactionBeginを呼び出した後、DatabaseTransactionCommitを呼び出さずにデータベースを閉じたりEAを停止したりすると、その間の全ての変更は保存されません。
  2. データベースのロック(Database is locked):
    トランザクションが開かれたままの状態(CommitもRollbackもされていない状態)で、他のプロセスや別の関数が同じデータベースに書き込もうとすると、「Database is locked」エラーが発生します。処理が終わったら必ず即座にCommitすることを徹底してください。
  3. エラーハンドリング:
    サンプルコードにあるように、ループ内でのINSERTに一つでも失敗した場合は、不完全なデータを残さないようDatabaseTransactionRollbackを呼び出すのがクオンツエンジニアとしての作法です。

5. 【重要】自動売買における約定スピードと環境の罠

データベース操作の最適化はEA内部の処理速度を劇的に改善しますが、実際のトレード収益に直結する「約定スピード」については、プログラムの書き換えだけでは限界があります。

自宅のPCや一般的なWi-Fi環境で自動売買を行う場合、どんなにコードを高速化しても、ブローカーのサーバーに注文が届くまでの物理的な「ネットワーク遅延(レイテンシ)」が致命的なボトルネックとなります。FX市場の価格は1ミリ秒単位で変動しており、自宅の回線による数十〜数百ミリ秒の遅延は、スリッページを増大させ、期待値を著しく低下させます。

プロレベルの運用を目指すのであれば、ブローカーの取引サーバーに物理的に近いデータセンターに設置された「専用VPS」の導入は必須です。ネットワーク遅延を極限まで排除した環境と、本記事で解説したような高速なデータ処理アルゴリズムを組み合わせることで、初めてシステマティックな優位性を実運用で発揮することが可能になります。

💡 この記事の内容を実運用で活かすには?

この記事の内容を実運用で活かすには、正しい環境が必要です。
特にVPSを使わないと、このロジックは再現できません。

コメント

タイトルとURLをコピーしました