トップ  >  リファレンス  >  ストラテジーAPI  >  オーダーとポジション  >  オーダー状態管理
オーダー状態管理


オーダーのメッセージや状態変化のワークフローについてはオーダー状態のページを参照して下さい。
このページでは、オーダー変更のやり方について焦点を当てた内容になります。
オーダー変更のモニタリングする方法は2種類あります。
  • onMessageのコールバックメソッド
  • IOrder.waitForUpdateメソッド

基本的に、どちらの方法でも同様に機能しますが、
  • 急を要する操作(ストップロス設定やクローズオーダー等)の場合、IOrder.waitForUpdateはas the advantage of keeping all the logic in the same place
  • 急を要さない操作(ストップロス設定の解除や条件付きオーダー)の場合、IOrder.waitForUpdateを使用するべきではありません。
    なぜなら、mostly it is non-deterministic when the operation will take place
    and the execution of the method holds up the execution of the rest of the strategy logic.
  • onMessageは特定アカウントの全てのオーダー変化についてメッセージを受け取れる利点がありますが、 IOrder.waitForUpdateは1つのオーダーでのみ機能します。


onMessageの使用例

onMessageメソッドは全てのオーダー変化メッセージ(オーダー状態か値が変化した時)を受信します。
このコールバックメソッドはalso the place where one can apply some strategy logic on certain order changes.


成行オーダー約定のフロー(onMessage)

以下例は、2つの成行オーダー送信し、サーバー側で変化があると直ぐにログメッセージ出力されます。



public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    engine.submitOrder("orderValid"  , Instrument.EURUSD, OrderCommand.BUY,  0.001);
    engine.submitOrder("orderInvalid", Instrument.EURUSD, OrderCommand.BUY, 10.000);
}

public void onMessage(IMessage message) throws JFException {
    
    switch(message.getType()){
        case ORDER_SUBMIT_OK : 
            print("オーダー受信: "     + message.getOrder());
            break;
        case ORDER_SUBMIT_REJECTED : 
            print("オーダー受信拒否: " + message.getOrder());
            break;
        case ORDER_FILL_OK : 
            print("オーダー約定: "     + message.getOrder());
            break;
        case ORDER_FILL_REJECTED : 
            print("オーダー約定拒否: " + message.getOrder());
            break;
        default:
            break;
    }
    print("<html><font color=\"gray\">"+message+"</font>");
}


注意:2つめのオーダーは無効な取引量で送信します。


サンプルソースコード:TestOnMessage.java







約定後にストップロスを更新(onMessage)

ストップロス2pips設定で成行オーダーを送信し、約定されたら直ぐにストップロス価格をオープン価格から2pips下に正確に調整します。


public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    double price = context.getHistory().getLastTick(Instrument.EURUSD).getBid();
    
    // ストップロス2pipsとリミット2pipsとスリップ20pipsでオーダーする
    order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001, 0, 20, 
            price - 0.0002, price + 0.0002);
}

public void onMessage(IMessage message) throws JFException {
    // ストップロスをオープン価格から5pipsに更新
    if(message.getOrder() == order && message.getType() == IMessage.Type.ORDER_FILL_OK){
        order.setStopLossPrice(order.getOpenPrice() - 0.0005);  
    }
    print("<html><font color=\"gray\">"+message+"</font>");
    
}



サンプルソースコード:TestOnMessageSL.java







キューでストップロス更新(onMessage)

前回の例を変更して、ストップロス更新をonMessageの代わりにonTickメソッドで行われるようにします。
ユーザーが全てのオーダーを一か所(例えばonTickメソッド内)で処理したい場合に、便利なやり方です。


private Queue<IOrder> justFilledOrders = new ConcurrentLinkedQueue<IOrder>();

public void onMessage(IMessage message) throws JFException {

    // JForex-API 2.6.38ではonMessageでオーダー変更出来ないので、オーダー変更要求をキューに入れ次のonTickで処理します
    if(message.getOrder() == order && message.getType() == IMessage.Type.ORDER_FILL_OK){
        justFilledOrders.add(message.getOrder());
    }
    
    print("<html><font color=\"gray\">"+message+"</font>");
    
}

public void onTick(Instrument instrument, ITick tick) throws JFException {                
    // 約定されたオーダーを処理します
    while(!justFilledOrders.isEmpty()){
        IOrder filledOrder = justFilledOrders.poll();
        if(filledOrder == order){
            // ストップロスをオープン価格から5pipsに更新
            order.setStopLossPrice(order.getOpenPrice() - 0.0005);  
        }
    }
}



サンプルソースコード:TestOnMessageSLQueue.java







オーダー再送信(onMessage)

以下例は、ストラテジー起動時に約定拒否されるような取引数量で成行オーダーを送信し、
引数量を増やして再オーダーしてオーダー約定されるか、またはmaxOrderResubmitCountで指定した回数分再オーダーするまで継続します。


@Configurable("再オーダー送信回数上限")
public int maxOrderResubmitCount = 5;

private Map<IOrder,Integer> resubmitAttempts = new HashMap<IOrder,Integer>();

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    IOrder order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, - 0.002);
    resubmitAttempts.put(order, 0);
}

public void onMessage(IMessage message) throws JFException {

    IOrder order = message.getOrder();
    
    if(message.getType() == IMessage.Type.ORDER_SUBMIT_REJECTED){
        console.getOut().println(message);
        Integer attempts = resubmitAttempts.get(order);
        if(attempts == null){
            console.getWarn().println("Rejected order was not created by this strategy.");
        } else if (attempts > maxOrderResubmitCount){
            console.getWarn().println("約定拒否の再オーダー送信回数上限を超えました");
        } else {
            resubmitAttempts.remove(order);
            IOrder newOrder = engine.submitOrder(order.getLabel(), order.getInstrument(),
                                                 order.getOrderCommand(), order.getAmount() + 0.001);
            resubmitAttempts.put(newOrder, ++attempts);
            console.getOut().println("再送信オーダー: " + newOrder +
                                     " 残送信回数: " +(maxOrderResubmitCount - attempts + 1));
        }
    }        
}


注意:意図的に約定拒否されるようマイナスロットでオーダーしていますが、APIのバージョンによってはマイナスロットオーダーするとストラテジーが停止します。


サンプルソースコード:TestOnMessageResubmit.java







IOrder.waitForUpdateの使用例

IOrder.waitForUpdateはストップロス価格の更新やクローズオーダー等のように急を要する操作を行う時に役に立ちます。
待機時間を数秒以上に設定する事はお勧めできません、IOrder.waitForUpdateの実行時間が長くなるとティックがスキップされてしまうからです。


成行オーダー約定のフロー(IOrder.waitForUpdate)

以下例は、IOrder.waitForUpdateメソッドを使用して、成行オーダー送信後にIOrder.State.FILLEDまで更新される事を確認します。


public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    IOrder order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001);
    print(String.format("オーダー送信後: オーダー状態=%s, オープン価格=%.5f, オーダー作成時間=%s",
            order.getState(), order.getOpenPrice(), DateUtils.format(order.getCreationTime())));
    
    order.waitForUpdate(2000); // オーダー状態OPENED待ちの為の2秒待ち
    print(String.format("オーダー状態更新後(OPENED): オーダー状態=%s, オープン価格=%.5f, オーダー作成時間=%s",
            order.getState(), order.getOpenPrice(), DateUtils.format(order.getCreationTime())));
    
    order.waitForUpdate(2000); // オーダー状態FILLED待ちの為の2秒待ち
    print(String.format("オーダー状態更新後(FILLED): オーダー状態=%s, オープン価格=%.5f, 約定時間=%s",
            order.getState(),order.getOpenPrice(), DateUtils.format(order.getFillTime())));
     
}




サンプルソースコード:TestWaitForUpdate.java


オーダー状態がFILLEDになるまで待つ方法もあります(APIのバージョンによっては使用出来ません)。


order.waitForUpdate(2000, IOrder.State.FILLED); // オーダー状態FILLED待ちの為の最大2秒待ち






ストップロス更新(IOrder.waitForUpdate)

成行オーダーが約定されるまで待ち、オープン価格に応じてストップロス価格を更新します。


public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    double price = context.getHistory().getLastTick(Instrument.EURUSD).getBid();
    
    // ストラテジー起動時にストップロス付き成行オーダーを送信し、約定後直ぐにストップロスを更新します。
    IOrder order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001, 0, 20, 
            price - 0.0005, price + 0.0005);
    order.waitForUpdate(2000); // オーダー状態OPENED待ちの為の2秒待ち
    order.waitForUpdate(2000); // オーダー状態FILLED待ちの為の2秒待ち
    print(String.format("約定後: state=%s, オープン価格=%.5f, 約定時間=%s, ストップロス=%.5f",
            order.getState(),order.getOpenPrice(), DateUtils.format(order.getFillTime()), order.getStopLossPrice()));
    
    // オープン価格から5pipsの所にストップロス調整
    order.setStopLossPrice(order.getOpenPrice() - 0.0005);
    order.waitForUpdate(2000); // ストップロス価格更新待ちの為の2秒待ち
    print(String.format("ストップロス更新後: state=%s, オープン価格=%.5f, 約定時間=%s, ストップロス=%.5f",
            order.getState(),order.getOpenPrice(), DateUtils.format(order.getFillTime()), order.getStopLossPrice()));
     
}




サンプルソースコード:TestWaitForUpdateSL.java






オーダー再送信(IOrder.waitForUpdate)

以下例は、何らかの理由で約定拒否された場合の対処方法の例です。
単純に、約定拒否される取引数量でオーダー送信し、約定拒否されたらオーダー再送信します。


public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    
    IOrder order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, -0.001);
    
    IMessage message = order.waitForUpdate(2000, IOrder.State.OPENED);// オーダー状態OPENED待ちの為の2秒待ち
    // 約定拒否された後のオーダー再送信
    if(message.getType() == IMessage.Type.ORDER_SUBMIT_REJECTED){
        order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, 0.001);
        message = order.waitForUpdate(2000, IOrder.State.OPENED);// オーダー状態OPENED待ちの為の2秒待ち
    }

    print(String.format("更新後: オーダー状態=%s, メッセージ=%s", order.getState(), message));        
     
}


IMessage.Typeをチェックする代わりに、IOrder.waitForUpdate実行後にIOrder.Stateする事も出来ます。

注意:意図的に約定拒否されるようマイナスロットでオーダーしていますが、APIのバージョンによってはマイナスロットオーダーするとストラテジーが停止します。


サンプルソースコード:TestWaitForUpdateResubmit.java




スポンサーリンク

スポンサーリンク
検索
リファレンスツリー


Copyright ©2016 JForexAPIで自動売買させ隊! All Rights Reserved.


Top

inserted by FC2 system