Skip to content
All library documents

Testing Deribit Order Execution with IOC and Post-Only Orders

Code NautilusTrader

Summary

This example shows how to configure a live trading node to test order handling on the Deribit testnet. At startup, the built-in tester can open a position with an immediate-or-cancel order, then maintain post-only limit orders on both sides of the book. It subscribes to quote and trade data for a Bitcoin perpetual instrument and enables order cancellation and position closing when the strategy stops.

The example demonstrates execution and lifecycle settings rather than a trading signal: it explicitly says the strategy has no alpha advantage and is not intended for production. Its configuration also enables a bypassed risk engine and sets dry run to false, so orders are sent to the configured testnet and shutdown actions can affect test positions. The code cautions that changing the environment or using real funds could make these operations consequential. It reports no performance evaluation or evidence that the order behavior improves trading results.

Key ideas

  • The example uses an immediate-or-cancel order to open a position when the strategy starts.
  • It maintains post-only buy and sell limit quotes using market data subscriptions.
  • On shutdown, the configured strategy cancels orders and closes positions.
  • The tester is intended for execution checks and provides no trading edge or performance evidence.
  • Dry-run and environment settings determine whether orders and shutdown actions are sent.

Tags

Full text
# exec_tester.py


```py
#!/usr/bin/env python3
# -------------------------------------------------------------------------------------------------
#  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
#  https://nautechsystems.io
#
#  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
#  You may not use this file except in compliance with the License.
#  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
# -------------------------------------------------------------------------------------------------
"""
Test Deribit execution with the built-in ExecTester strategy.

This example connects to the Deribit testnet and places live testnet orders. On start it
opens a position with an IOC order, then maintains post-only limit quotes on both sides
of the book. On stop it cancels all orders and closes all positions. The strategy has no
alpha advantage whatsoever and is not intended for production trading.

"""

from __future__ import annotations

from decimal import Decimal

from nautilus_trader.adapters.deribit import DeribitDataClientConfig
from nautilus_trader.adapters.deribit import DeribitDataClientFactory
from nautilus_trader.adapters.deribit import DeribitEnvironment
from nautilus_trader.adapters.deribit import DeribitExecutionClientConfig
from nautilus_trader.adapters.deribit import DeribitExecutionClientFactory
from nautilus_trader.adapters.deribit import DeribitProductType
from nautilus_trader.common import Environment
from nautilus_trader.config import LiveRiskEngineConfig
from nautilus_trader.live import LiveNode
from nautilus_trader.model import AccountId
from nautilus_trader.model import ClientId
from nautilus_trader.model import InstrumentId
from nautilus_trader.model import Quantity
from nautilus_trader.model import StrategyId
from nautilus_trader.model import TimeInForce
from nautilus_trader.model import TraderId
from nautilus_trader.testkit import ExecTesterConfig


# WARNING: With DRY_RUN = False, this tester submits orders to the configured
# environment and may use real funds. Set DRY_RUN = True to connect without
# submitting orders or sending shutdown cancel/close commands.
DRY_RUN = False
DERIBIT = "DERIBIT"
TRADER_ID = TraderId.from_str("TESTER-001")
ACCOUNT_ID = AccountId.from_str("DERIBIT-001")
STRATEGY_ID = StrategyId.from_str("EXEC_TESTER-001")
INSTRUMENT_ID = InstrumentId.from_str(f"BTC-PERPETUAL.{DERIBIT}")
PRODUCT_TYPES = [DeribitProductType.FUTURE]
ORDER_QTY = "10"
TOB_OFFSET_TICKS = 500


def main() -> None:
    """
    Run the example.
    """
    node = (
        LiveNode.builder("DERIBIT-EXEC-TESTER-001", TRADER_ID, Environment.LIVE)
        .with_reconciliation(reconciliation=True)
        .with_risk_engine_config(LiveRiskEngineConfig(bypass=True))
        .add_data_client(
            None,
            DeribitDataClientFactory(),
            DeribitDataClientConfig(
                product_types=PRODUCT_TYPES,
                environment=DeribitEnvironment.TESTNET,
            ),
        )
        .add_exec_client(
            None,
            DeribitExecutionClientFactory(),
            DeribitExecutionClientConfig(
                account_id=ACCOUNT_ID,
                product_types=PRODUCT_TYPES,
                environment=DeribitEnvironment.TESTNET,
            ),
        )
        .build()
    )
    node.add_builtin_strategy(
        "ExecTester",
        ExecTesterConfig(
            strategy_id=STRATEGY_ID,
            instrument_id=INSTRUMENT_ID,
            client_id=ClientId.from_str(DERIBIT),
            external_order_instrument_ids=[INSTRUMENT_ID],
            order_qty=Quantity.from_str(ORDER_QTY),
            subscribe_quotes=True,
            subscribe_trades=True,
            open_position_on_start_qty=Decimal(ORDER_QTY),
            open_position_on_first_quote=True,
            open_position_time_in_force=TimeInForce.IOC,
            enable_limit_buys=True,
            enable_limit_sells=True,
            tob_offset_ticks=TOB_OFFSET_TICKS,
            use_post_only=True,
            cancel_orders_on_stop=True,
            close_positions_on_stop=True,
            reduce_only_on_stop=False,
            dry_run=DRY_RUN,
            log_data=False,
        ),
    )

    node.run()


if __name__ == "__main__":
    main()

```

Shown in full with attribution under the source's licence. Licence: LGPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.