From 5258143ae2492c4789b43054dc9035b7ba37282e Mon Sep 17 00:00:00 2001 From: rsmb7z <105105941+rsmb7z@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:09:27 +0300 Subject: [PATCH] Implement CommissionModel (#1584) --- nautilus_trader/adapters/sandbox/execution.py | 2 + nautilus_trader/backtest/engine.pyx | 6 + nautilus_trader/backtest/exchange.pxd | 3 + nautilus_trader/backtest/exchange.pyx | 6 + nautilus_trader/backtest/matching_engine.pxd | 2 + nautilus_trader/backtest/matching_engine.pyx | 31 ++--- nautilus_trader/backtest/models.pxd | 22 ++++ nautilus_trader/backtest/models.pyx | 109 ++++++++++++++++++ .../backtest/test_commission_model.py | 105 +++++++++++++++++ .../backtest/test_exchange_bitmex.py | 2 + ...est_exchange_bracket_if_touched_entries.py | 2 + .../unit_tests/backtest/test_exchange_cash.py | 2 + .../backtest/test_exchange_contingencies.py | 2 + .../backtest/test_exchange_l2_mbp.py | 2 + .../backtest/test_exchange_margin.py | 4 + .../backtest/test_exchange_stop_limits.py | 2 + .../backtest/test_exchange_trailing_stops.py | 2 + .../backtest/test_matching_engine.py | 2 + tests/unit_tests/execution/test_algorithm.py | 2 + .../execution/test_emulator_list.py | 2 + tests/unit_tests/trading/test_strategy.py | 2 + tests/unit_tests/trading/test_trader.py | 2 + 22 files changed, 294 insertions(+), 20 deletions(-) create mode 100644 tests/unit_tests/backtest/test_commission_model.py diff --git a/nautilus_trader/adapters/sandbox/execution.py b/nautilus_trader/adapters/sandbox/execution.py index 76d9f5e91ed8..1440a5d24bcc 100644 --- a/nautilus_trader/adapters/sandbox/execution.py +++ b/nautilus_trader/adapters/sandbox/execution.py @@ -22,6 +22,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.cache.cache import Cache from nautilus_trader.common.component import LiveClock @@ -119,6 +120,7 @@ def __init__( msgbus=self._msgbus, cache=cache, fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), latency_model=LatencyModel(0), clock=self.test_clock, frozen_account=True, # <-- Freezing account diff --git a/nautilus_trader/backtest/engine.pyx b/nautilus_trader/backtest/engine.pyx index f4c8853bc862..6d99e38061ba 100644 --- a/nautilus_trader/backtest/engine.pyx +++ b/nautilus_trader/backtest/engine.pyx @@ -41,7 +41,9 @@ from nautilus_trader.backtest.data_client cimport BacktestDataClient from nautilus_trader.backtest.data_client cimport BacktestMarketDataClient from nautilus_trader.backtest.exchange cimport SimulatedExchange from nautilus_trader.backtest.execution_client cimport BacktestExecClient +from nautilus_trader.backtest.models cimport CommissionModel from nautilus_trader.backtest.models cimport FillModel +from nautilus_trader.backtest.models cimport InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models cimport LatencyModel from nautilus_trader.backtest.modules cimport SimulationModule from nautilus_trader.cache.base cimport CacheFacade @@ -366,6 +368,7 @@ cdef class BacktestEngine: leverages: dict[InstrumentId, Decimal] | None = None, modules: list[SimulationModule] | None = None, fill_model: FillModel | None = None, + commission_model: CommissionModel = InstrumentSpecificPercentCommissionModel(), latency_model: LatencyModel | None = None, book_type: BookType = BookType.L1_MBP, routing: bool = False, @@ -402,6 +405,8 @@ cdef class BacktestEngine: The simulation modules to load into the exchange. fill_model : FillModel, optional The fill model for the exchange. + commission_model : CommissionModel, optional + The commission model for the exchange. latency_model : LatencyModel, optional The latency model for the exchange. book_type : BookType, default ``BookType.L1_MBP`` @@ -463,6 +468,7 @@ cdef class BacktestEngine: msgbus=self.kernel.msgbus, cache=self.kernel.cache, fill_model=fill_model, + commission_model=commission_model, latency_model=latency_model, book_type=book_type, clock=self.kernel.clock, diff --git a/nautilus_trader/backtest/exchange.pxd b/nautilus_trader/backtest/exchange.pxd index 561376f7397e..cee06a09514a 100644 --- a/nautilus_trader/backtest/exchange.pxd +++ b/nautilus_trader/backtest/exchange.pxd @@ -18,6 +18,7 @@ from libc.stdint cimport uint64_t from nautilus_trader.accounting.accounts.base cimport Account from nautilus_trader.backtest.execution_client cimport BacktestExecClient from nautilus_trader.backtest.matching_engine cimport OrderMatchingEngine +from nautilus_trader.backtest.models cimport CommissionModel from nautilus_trader.backtest.models cimport FillModel from nautilus_trader.backtest.models cimport LatencyModel from nautilus_trader.cache.cache cimport Cache @@ -78,6 +79,8 @@ cdef class SimulatedExchange: """The latency model for the exchange.\n\n:returns: `LatencyModel`""" cdef readonly FillModel fill_model """The fill model for the exchange.\n\n:returns: `FillModel`""" + cdef readonly CommissionModel commission_model + """The commission model for the exchange.\n\n:returns: `CommissionModel`""" cdef readonly bint bar_execution """If bars should be processed by the matching engine(s) (and move the market).\n\n:returns: `bool`""" cdef readonly bint reject_stop_orders diff --git a/nautilus_trader/backtest/exchange.pyx b/nautilus_trader/backtest/exchange.pyx index 9c74931b0960..525d7f5aae21 100644 --- a/nautilus_trader/backtest/exchange.pyx +++ b/nautilus_trader/backtest/exchange.pyx @@ -24,6 +24,7 @@ from libc.stdint cimport uint64_t from nautilus_trader.accounting.accounts.base cimport Account from nautilus_trader.backtest.execution_client cimport BacktestExecClient from nautilus_trader.backtest.matching_engine cimport OrderMatchingEngine +from nautilus_trader.backtest.models cimport CommissionModel from nautilus_trader.backtest.models cimport FillModel from nautilus_trader.backtest.models cimport LatencyModel from nautilus_trader.backtest.modules cimport SimulationModule @@ -88,6 +89,8 @@ cdef class SimulatedExchange: The read-only cache for the exchange. fill_model : FillModel The fill model for the exchange. + commission_model : CommissionModel + The commission model for the matching engine. latency_model : LatencyModel, optional The latency model for the exchange. clock : TestClock @@ -144,6 +147,7 @@ cdef class SimulatedExchange: CacheFacade cache not None, TestClock clock not None, FillModel fill_model not None, + CommissionModel commission_model not None, LatencyModel latency_model = None, BookType book_type = BookType.L1_MBP, bint frozen_account = False, @@ -193,6 +197,7 @@ cdef class SimulatedExchange: self.use_random_ids = use_random_ids self.use_reduce_only = use_reduce_only self.fill_model = fill_model + self.commission_model = commission_model self.latency_model = latency_model # Load modules @@ -328,6 +333,7 @@ cdef class SimulatedExchange: instrument=instrument, raw_id=len(self.instruments), fill_model=self.fill_model, + commission_model=self.commission_model, book_type=self.book_type, oms_type=self.oms_type, account_type=self.account_type, diff --git a/nautilus_trader/backtest/matching_engine.pxd b/nautilus_trader/backtest/matching_engine.pxd index 3cfdad9d16b2..470e77bb85cd 100644 --- a/nautilus_trader/backtest/matching_engine.pxd +++ b/nautilus_trader/backtest/matching_engine.pxd @@ -17,6 +17,7 @@ from libc.stdint cimport int64_t from libc.stdint cimport uint32_t from libc.stdint cimport uint64_t +from nautilus_trader.backtest.models cimport CommissionModel from nautilus_trader.backtest.models cimport FillModel from nautilus_trader.cache.base cimport CacheFacade from nautilus_trader.common.component cimport Clock @@ -76,6 +77,7 @@ cdef class OrderMatchingEngine: cdef OrderBook _opening_auction_book cdef OrderBook _closing_auction_book cdef FillModel _fill_model + cdef CommissionModel _commission_model # cdef object _auction_match_algo cdef bint _bar_execution cdef bint _reject_stop_orders diff --git a/nautilus_trader/backtest/matching_engine.pyx b/nautilus_trader/backtest/matching_engine.pyx index 4504e820dc50..3fff47bb3900 100644 --- a/nautilus_trader/backtest/matching_engine.pyx +++ b/nautilus_trader/backtest/matching_engine.pyx @@ -21,6 +21,7 @@ import uuid from cpython.datetime cimport timedelta from libc.stdint cimport uint64_t +from nautilus_trader.backtest.models cimport CommissionModel from nautilus_trader.backtest.models cimport FillModel from nautilus_trader.cache.base cimport CacheFacade from nautilus_trader.common.component cimport LogColor @@ -110,6 +111,8 @@ cdef class OrderMatchingEngine: The raw integer ID for the instrument. fill_model : FillModel The fill model for the matching engine. + commission_model : CommissionModel + The commission model for the matching engine. book_type : BookType The order book type for the engine. oms_type : OmsType @@ -150,6 +153,7 @@ cdef class OrderMatchingEngine: Instrument instrument not None, uint32_t raw_id, FillModel fill_model not None, + CommissionModel commission_model not None, BookType book_type, OmsType oms_type, AccountType account_type, @@ -187,6 +191,7 @@ cdef class OrderMatchingEngine: self._use_reduce_only = use_reduce_only # self._auction_match_algo = auction_match_algo self._fill_model = fill_model + self._commission_model = commission_model self._book = OrderBook( instrument_id=instrument.id, book_type=book_type, @@ -1765,27 +1770,13 @@ cdef class OrderMatchingEngine: order.liquidity_side = liquidity_side # Calculate commission - cdef double notional = self.instrument.notional_value( - quantity=last_qty, - price=last_px, - use_quote_for_inverse=False, - ).as_f64_c() - - cdef double commission_f64 - if order.liquidity_side == LiquiditySide.MAKER: - commission_f64 = notional * float(self.instrument.maker_fee) - elif order.liquidity_side == LiquiditySide.TAKER: - commission_f64 = notional * float(self.instrument.taker_fee) - else: - raise ValueError( - f"invalid `LiquiditySide`, was {liquidity_side_to_str(order.liquidity_side)}" - ) - cdef Money commission - if self.instrument.is_inverse: # Not using quote for inverse (see above): - commission = Money(commission_f64, self.instrument.base_currency) - else: - commission = Money(commission_f64, self.instrument.quote_currency) + commission = self._commission_model.get_commission( + order=order, + fill_qty=last_qty, + fill_px=last_px, + instrument=self.instrument, + ) self._generate_order_filled( order=order, diff --git a/nautilus_trader/backtest/models.pxd b/nautilus_trader/backtest/models.pxd index 1da578aa51ce..931c03122c37 100644 --- a/nautilus_trader/backtest/models.pxd +++ b/nautilus_trader/backtest/models.pxd @@ -15,6 +15,12 @@ from libc.stdint cimport uint64_t +from nautilus_trader.model.instruments.base cimport Instrument +from nautilus_trader.model.objects cimport Money +from nautilus_trader.model.objects cimport Price +from nautilus_trader.model.objects cimport Quantity +from nautilus_trader.model.orders.base cimport Order + cdef class FillModel: cdef readonly double prob_fill_on_limit @@ -40,3 +46,19 @@ cdef class LatencyModel: """The latency (nanoseconds) for order update messages to reach the exchange.\n\n:returns: `int`""" cdef readonly uint64_t cancel_latency_nanos """The latency (nanoseconds) for order cancel messages to reach the exchange.\n\n:returns: `int`""" + + +cdef class CommissionModel: + cpdef Money get_commission(self, Order order, Quantity fill_qty, Price fill_px, Instrument instrument) + + +cdef class InstrumentSpecificPercentCommissionModel(CommissionModel): + """ + Provide a commission model for trades based on a percentage of the notional value + of the trade. + + """ + +cdef class FixedCommissionModel(CommissionModel): + cdef Money commission + """The constant commission.""" diff --git a/nautilus_trader/backtest/models.pyx b/nautilus_trader/backtest/models.pyx index 7c170d5fa162..d81bb0ed1cf3 100644 --- a/nautilus_trader/backtest/models.pyx +++ b/nautilus_trader/backtest/models.pyx @@ -18,6 +18,13 @@ import random from libc.stdint cimport uint64_t from nautilus_trader.core.correctness cimport Condition +from nautilus_trader.core.rust.model cimport LiquiditySide +from nautilus_trader.model.functions cimport liquidity_side_to_str +from nautilus_trader.model.instruments.base cimport Instrument +from nautilus_trader.model.objects cimport Money +from nautilus_trader.model.objects cimport Price +from nautilus_trader.model.objects cimport Quantity +from nautilus_trader.model.orders.base cimport Order cdef uint64_t NANOSECONDS_IN_MILLISECOND = 1_000_000 @@ -154,3 +161,105 @@ cdef class LatencyModel: self.insert_latency_nanos = base_latency_nanos + insert_latency_nanos self.update_latency_nanos = base_latency_nanos + update_latency_nanos self.cancel_latency_nanos = base_latency_nanos + cancel_latency_nanos + + +cdef class CommissionModel: + """ + Provide an abstract commission model for trades. + """ + cpdef Money get_commission( + self, + Order order, + Quantity fill_qty, + Price fill_px, + Instrument instrument, + ): + """ + Return the commission for a trade. + + Parameters + ---------- + order : Order + The order to calculate the commission for. + fill_qty : Quantity + The fill quantity of the order. + fill_px : Price + The fill price of the order. + instrument : Instrument + The instrument for the order. + + Returns + ------- + Money + + """ + raise NotImplementedError("Method 'get_commission' must be implemented in a subclass.") + + +cdef class InstrumentSpecificPercentCommissionModel(CommissionModel): + """ + Provide a commission model for trades based on a percentage of the notional value + of the trade. + + """ + + cpdef Money get_commission( + self, + Order order, + Quantity fill_qty, + Price fill_px, + Instrument instrument, + ): + cdef double notional = instrument.notional_value( + quantity=fill_qty, + price=fill_px, + use_quote_for_inverse=False, + ).as_f64_c() + + cdef double commission_f64 + if order.liquidity_side == LiquiditySide.MAKER: + commission_f64 = notional * float(instrument.maker_fee) + elif order.liquidity_side == LiquiditySide.TAKER: + commission_f64 = notional * float(instrument.taker_fee) + else: + raise ValueError( + f"invalid `LiquiditySide`, was {liquidity_side_to_str(order.liquidity_side)}" + ) + + cdef Money commission + if instrument.is_inverse: # Not using quote for inverse (see above): + commission = Money(commission_f64, instrument.base_currency) + else: + commission = Money(commission_f64, instrument.quote_currency) + + return commission + + +cdef class FixedCommissionModel(CommissionModel): + """ + Provides a fixed commission model for trades. + + Parameters + ---------- + commission : Money + The fixed commission amount for trades. + + Raises + ------ + ValueError + If `commission` is not a positive amount. + + """ + + def __init__(self, Money commission): + Condition.type(commission, Money, "commission") + self.commission = commission + + cpdef Money get_commission( + self, + Order order, + Quantity fill_qty, + Price fill_px, + Instrument instrument, + ): + return self.commission diff --git a/tests/unit_tests/backtest/test_commission_model.py b/tests/unit_tests/backtest/test_commission_model.py new file mode 100644 index 000000000000..d55c99a71a0f --- /dev/null +++ b/tests/unit_tests/backtest/test_commission_model.py @@ -0,0 +1,105 @@ +# ------------------------------------------------------------------------------------------------- +# Copyright (C) 2015-2024 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. +# ------------------------------------------------------------------------------------------------- + +import pytest + +# fmt: off +from nautilus_trader.backtest.models import FixedCommissionModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel +from nautilus_trader.model.currencies import USD +from nautilus_trader.model.enums import OrderSide +from nautilus_trader.model.instruments.base import Instrument +from nautilus_trader.model.objects import Money +from nautilus_trader.model.objects import Price +from nautilus_trader.model.orders import Order +from nautilus_trader.test_kit.providers import TestInstrumentProvider +from nautilus_trader.test_kit.stubs.execution import TestExecStubs + + +# fmt: on + + +@pytest.fixture() +def instrument() -> Instrument: + return TestInstrumentProvider.default_fx_ccy("EUR/USD") + + +@pytest.fixture() +def buy_order(instrument: Instrument) -> Order: + return TestExecStubs.make_filled_order( + instrument=instrument, + order_side=OrderSide.BUY, + ) + + +@pytest.fixture() +def sell_order(instrument: Instrument) -> Order: + return TestExecStubs.make_filled_order( + instrument=instrument, + order_side=OrderSide.SELL, + ) + + +def test_fixed_commission(buy_order, instrument): + # Arrange + expected = Money(1, USD) + commission_model = FixedCommissionModel(expected) + + # Act + commission = commission_model.get_commission( + buy_order, + buy_order.quantity, + Price.from_str("1.1234"), + instrument, + ) + + # Assert + assert commission == expected + + +def test_instrument_percent_commission_maker(instrument, buy_order): + # Arrange + commission_model = InstrumentSpecificPercentCommissionModel() + expected = buy_order.quantity * buy_order.price * instrument.maker_fee + + # Act + commission = commission_model.get_commission( + buy_order, + buy_order.quantity, + buy_order.price, + instrument, + ) + + # Assert + assert isinstance(commission, Money) + assert commission.as_decimal() == expected + + +def test_instrument_percent_commission_taker(instrument, sell_order): + # Arrange + commission_model = InstrumentSpecificPercentCommissionModel() + expected = sell_order.quantity * sell_order.price * instrument.taker_fee + + # Act + commission = commission_model.get_commission( + sell_order, + sell_order.quantity, + sell_order.price, + instrument, + ) + + # Assert + assert isinstance(commission, Money) + assert commission.as_decimal() == expected diff --git a/tests/unit_tests/backtest/test_exchange_bitmex.py b/tests/unit_tests/backtest/test_exchange_bitmex.py index d52638222524..07422fdefbdf 100644 --- a/tests/unit_tests/backtest/test_exchange_bitmex.py +++ b/tests/unit_tests/backtest/test_exchange_bitmex.py @@ -18,6 +18,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -103,6 +104,7 @@ def setup(self): instruments=[XBTUSD_BITMEX], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), clock=self.clock, latency_model=LatencyModel(0), ) diff --git a/tests/unit_tests/backtest/test_exchange_bracket_if_touched_entries.py b/tests/unit_tests/backtest/test_exchange_bracket_if_touched_entries.py index 431365d88625..00393ddee621 100644 --- a/tests/unit_tests/backtest/test_exchange_bracket_if_touched_entries.py +++ b/tests/unit_tests/backtest/test_exchange_bracket_if_touched_entries.py @@ -20,6 +20,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -107,6 +108,7 @@ def setup(self): instruments=[ETHUSDT_PERP_BINANCE], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_cash.py b/tests/unit_tests/backtest/test_exchange_cash.py index 4c04034522d5..9eafd90e4793 100644 --- a/tests/unit_tests/backtest/test_exchange_cash.py +++ b/tests/unit_tests/backtest/test_exchange_cash.py @@ -20,6 +20,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -99,6 +100,7 @@ def setup(self) -> None: instruments=[_AAPL_XNAS], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_contingencies.py b/tests/unit_tests/backtest/test_exchange_contingencies.py index f6c6f0988a86..7dfc3f8e23e4 100644 --- a/tests/unit_tests/backtest/test_exchange_contingencies.py +++ b/tests/unit_tests/backtest/test_exchange_contingencies.py @@ -18,6 +18,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -96,6 +97,7 @@ def setup(self): instruments=[ETHUSDT_PERP_BINANCE], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_l2_mbp.py b/tests/unit_tests/backtest/test_exchange_l2_mbp.py index 055c25d3b6bf..f85b90a359b9 100644 --- a/tests/unit_tests/backtest/test_exchange_l2_mbp.py +++ b/tests/unit_tests/backtest/test_exchange_l2_mbp.py @@ -20,6 +20,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -102,6 +103,7 @@ def setup(self): instruments=[_USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_margin.py b/tests/unit_tests/backtest/test_exchange_margin.py index 3ce5c6aedcf0..4fc8e5c07b26 100644 --- a/tests/unit_tests/backtest/test_exchange_margin.py +++ b/tests/unit_tests/backtest/test_exchange_margin.py @@ -21,6 +21,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.backtest.modules import SimulationModule from nautilus_trader.common.component import MessageBus @@ -128,6 +129,7 @@ def setup(self) -> None: instruments=[_USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, @@ -2729,6 +2731,7 @@ def test_adjust_account_when_account_frozen_does_not_change_balance(self) -> Non instruments=[_USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, @@ -3027,6 +3030,7 @@ def reset(self): instruments=[_USDJPY_SIM], modules=[self.module], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_stop_limits.py b/tests/unit_tests/backtest/test_exchange_stop_limits.py index 5175988c733a..ca1c1302be32 100644 --- a/tests/unit_tests/backtest/test_exchange_stop_limits.py +++ b/tests/unit_tests/backtest/test_exchange_stop_limits.py @@ -18,6 +18,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -100,6 +101,7 @@ def setup(self): instruments=[USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_exchange_trailing_stops.py b/tests/unit_tests/backtest/test_exchange_trailing_stops.py index 11520183a55d..999d6b823639 100644 --- a/tests/unit_tests/backtest/test_exchange_trailing_stops.py +++ b/tests/unit_tests/backtest/test_exchange_trailing_stops.py @@ -20,6 +20,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -109,6 +110,7 @@ def setup(self) -> None: instruments=[USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/backtest/test_matching_engine.py b/tests/unit_tests/backtest/test_matching_engine.py index 31fb2243290c..0d23be8694d5 100644 --- a/tests/unit_tests/backtest/test_matching_engine.py +++ b/tests/unit_tests/backtest/test_matching_engine.py @@ -19,6 +19,7 @@ from nautilus_trader.backtest.matching_engine import OrderMatchingEngine from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock from nautilus_trader.model.enums import AccountType @@ -59,6 +60,7 @@ def setup(self): instrument=self.instrument, raw_id=0, fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), book_type=BookType.L1_MBP, oms_type=OmsType.NETTING, account_type=AccountType.MARGIN, diff --git a/tests/unit_tests/execution/test_algorithm.py b/tests/unit_tests/execution/test_algorithm.py index 721971724f7b..2676fa589a64 100644 --- a/tests/unit_tests/execution/test_algorithm.py +++ b/tests/unit_tests/execution/test_algorithm.py @@ -21,6 +21,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.cache.cache import Cache from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -132,6 +133,7 @@ def setup(self) -> None: instruments=[ETHUSDT_PERP_BINANCE], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/execution/test_emulator_list.py b/tests/unit_tests/execution/test_emulator_list.py index ed1cf2dfbdfc..c6a006138af1 100644 --- a/tests/unit_tests/execution/test_emulator_list.py +++ b/tests/unit_tests/execution/test_emulator_list.py @@ -21,6 +21,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.cache.cache import Cache from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -130,6 +131,7 @@ def setup(self) -> None: instruments=[ETHUSDT_PERP_BINANCE], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, diff --git a/tests/unit_tests/trading/test_strategy.py b/tests/unit_tests/trading/test_strategy.py index 2fb4aadf2b6c..c705f8725712 100644 --- a/tests/unit_tests/trading/test_strategy.py +++ b/tests/unit_tests/trading/test_strategy.py @@ -25,6 +25,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.backtest.models import LatencyModel from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -125,6 +126,7 @@ def setup(self) -> None: instruments=[_USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), clock=self.clock, latency_model=LatencyModel(0), support_contingent_orders=False, diff --git a/tests/unit_tests/trading/test_trader.py b/tests/unit_tests/trading/test_trader.py index dbf52ba7e0f7..9be506e9de88 100644 --- a/tests/unit_tests/trading/test_trader.py +++ b/tests/unit_tests/trading/test_trader.py @@ -22,6 +22,7 @@ from nautilus_trader.backtest.exchange import SimulatedExchange from nautilus_trader.backtest.execution_client import BacktestExecClient from nautilus_trader.backtest.models import FillModel +from nautilus_trader.backtest.models import InstrumentSpecificPercentCommissionModel from nautilus_trader.common.actor import Actor from nautilus_trader.common.component import MessageBus from nautilus_trader.common.component import TestClock @@ -103,6 +104,7 @@ def setup(self) -> None: instruments=[USDJPY_SIM], modules=[], fill_model=FillModel(), + commission_model=InstrumentSpecificPercentCommissionModel(), clock=self.clock, )