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

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

MQL5でSQLiteデータベースを操作する際、データの整合性を保つために「トランザクション」という概念が不可欠です。DatabaseTransactionRollbackは、開始したトランザクション内で行われたすべての変更を取り消し、データベースをトランザクション開始前の状態に戻すための関数です。

実務開発において最もつまずきやすいのが、「複数のテーブルを同時に更新する処理」です。例えば、「取引履歴テーブルにレコードを追加し、同時に残高管理テーブルを更新する」という一連の処理(アトミックな操作)を行う場合、片方の書き込みが成功し、もう片方が失敗すると、データの辻褄が合わなくなります。

このような「中途半端な更新」を防ぐために、エラーが発生した瞬間にDatabaseTransactionRollbackを呼び出すことで、データベースに不正なデータが残るリスクをゼロにすることができます。プロのクオンツエンジニアは、DB操作の失敗を「単なるエラー」として放置せず、必ずこの関数でロールバック処理を行い、システムの信頼性を担保します。

2. 構文と戻り値

DatabaseTransactionRollbackの構文は非常にシンプルです。

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

パラメーター

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

戻り値

  • 成功した場合は true、失敗した場合は false を返します。
  • 失敗した場合は、GetLastError() を呼び出すことで詳細なエラーコードを確認できます。

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

以下のサンプルは、EA(エキスパートアドバイザー)が取引注文を出した後に、その結果をデータベースの2つの異なるテーブル(TradesLogs)に保存する例です。もし2つ目の保存に失敗した場合、1つ目の保存もなかったことにする(ロールバックする)処理を記述しています。

// データベースハンドルの宣言
int db_handle = INVALID_HANDLE;

void OnStart()
{
    // データベースを開く
    db_handle = DatabaseOpen("TradingStats.sqlite", DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE);

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

    // --- トランザクション開始 ---
    if(!DatabaseTransactionBegin(db_handle)) {
        Print("トランザクション開始失敗");
        DatabaseClose(db_handle);
        return;
    }

    // 1つ目のクエリ:取引結果の挿入
    string sql1 = "INSERT INTO Trades (Symbol, Profit) VALUES ('USDJPY', 150.50)";
    if(!DatabaseExecute(db_handle, sql1)) {
        Print("クエリ1失敗。ロールバックを実行します。");
        DatabaseTransactionRollback(db_handle); // 失敗したので元に戻す
        DatabaseClose(db_handle);
        return;
    }

    // 2つ目のクエリ:ログ情報の挿入(わざとエラーが出る状況などを想定)
    string sql2 = "INSERT INTO Logs (Message) VALUES ('Trade recorded successfully')";
    if(!DatabaseExecute(db_handle, sql2)) {
        Print("クエリ2失敗。全ての変更を破棄(ロールバック)します。");
        // ここでロールバックすることで、sql1の実行結果も消去される
        DatabaseTransactionRollback(db_handle); 
        DatabaseClose(db_handle);
        return;
    }

    // すべて成功した場合はコミットして確定させる
    if(DatabaseTransactionCommit(db_handle)) {
        Print("すべてのデータ保存に成功しました。");
    } else {
        Print("コミットに失敗。ロールバックします。");
        DatabaseTransactionRollback(db_handle);
    }

    DatabaseClose(db_handle);
}

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

  1. トランザクション未開始での実行
    DatabaseTransactionBeginを呼び出していない状態でDatabaseTransactionRollbackを実行しても、何も起こりません(あるいはエラーを返します)。必ず対になるように設計してください。

  2. データベースのロック
    トランザクションを開始したまま、CommitRollbackもせずに処理を抜けてしまうと、データベースファイルが「ロック(書き込み制限)」されたままになり、他のEAや外部ツールからDBを操作できなくなるバグが発生します。例外処理(if文の分岐)には必ずどちらかを記述しましょう。

  3. 読み取り専用モードでの使用
    DATABASE_OPEN_READONLYでデータベースを開いている場合、トランザクション操作自体が無効です。書き込みを行う際は必ず適切なフラグでオープンしてください。

  4. 自動コミットとの混同
    SQLiteは通常、1つのSQL文ごとに自動でコミットされますが、DatabaseTransactionBeginを呼んだ瞬間から、明示的にCommitするかRollbackするまでデータは「仮保存」の状態になります。この挙動を理解しておくことが重要です。

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

アルゴリズムトレードにおいて、データベース処理のような「ロジックの正確性」を追求することは極めて重要ですが、それ以上に収益を左右するのが「約定スピード」です。多くの日本人開発者が陥る罠は、自宅のPCや一般的な光回線でEAを稼働させてしまうことです。自宅環境では、ブローカーのサーバーとの間に数百ミリ秒の物理的なネットワーク遅延(レイテンシ)が発生し、これがスリッページを引き起こして、バックテストでは勝てていたロジックを「負けトレード」に変えてしまいます。

プロレベルのトレード環境を構築するには、ブローカーのデータセンターに近い場所に設置された「専用のVPS(仮想専用サーバー)」の利用が不可欠です。専用VPSであれば、ネットワーク遅延を1ミリ秒以下に抑え、機関投資家に匹敵する超高速な約定環境を手に入れることができます。データベースの整合性にこだわるのと同様に、インフラ環境の遅延を極限まで排除することが、自動売買で生き残るための絶対条件です。

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

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

コメント

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