From ce1a318c69a2a99a5e86886f12592e7c4d0eb031 Mon Sep 17 00:00:00 2001 From: Masanori HIRANO Date: Fri, 21 Apr 2023 11:10:01 +0900 Subject: [PATCH 1/5] WIP --- tests/pams/runners/test_sequential.py | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/pams/runners/test_sequential.py b/tests/pams/runners/test_sequential.py index ea4017ac..59fcc122 100644 --- a/tests/pams/runners/test_sequential.py +++ b/tests/pams/runners/test_sequential.py @@ -5,10 +5,13 @@ from typing import Dict from typing import Type from typing import cast +from unittest import mock import pytest from numpy.linalg import LinAlgError +from pams import LIMIT_ORDER +from pams import Order from pams.runners import Runner from pams.runners import SequentialRunner from tests.pams.runners.test_base import TestRunner @@ -1111,3 +1114,108 @@ def test_setup(self) -> None: ) with pytest.raises(ValueError): runner._setup() + + def test_collect_orders_from_normal_agents(self) -> None: + setting = { + "simulation": { + "markets": ["SpotMarket-1", "SpotMarket-2", "IndexMarket-I"], + "agents": [ + "FCNAgents-1", + "FCNAgents-2", + "FCNAgents-I", + "ArbitrageAgents", + ], + "sessions": [ + { + "sessionName": 0, + "iterationSteps": 100, + "withOrderPlacement": True, + "withOrderExecution": False, + "withPrint": True, + "maxNormalOrders": 3, + "MEMO": "The same number as #markets", + "maxHighFrequencyOrders": 0, + }, + { + "sessionName": 1, + "iterationSteps": 500, + "withOrderPlacement": True, + "withOrderExecution": True, + "withPrint": True, + "maxNormalOrders": 3, + "MEMO": "The same number as #markets", + "maxHighFrequencyOrders": 5, + "events": ["FundamentalPriceShock"], + }, + ], + }, + "FundamentalPriceShock": { + "class": "FundamentalPriceShock", + "target": "SpotMarket-1", + "triggerTime": 0, + "priceChangeRate": -0.3, + "enabled": True, + }, + "SpotMarket": { + "class": "Market", + "tickSize": 0.00001, + "marketPrice": 300.0, + "outstandingShares": 25000, + }, + "SpotMarket-1": {"extends": "SpotMarket"}, + "SpotMarket-2": {"extends": "SpotMarket"}, + "IndexMarket-I": { + "class": "IndexMarket", + "tickSize": 0.00001, + "marketPrice": 300.0, + "outstandingShares": 25000, + "markets": ["SpotMarket-1", "SpotMarket-2"], + }, + "FCNAgent": { + "class": "FCNAgent", + "numAgents": 100, + "markets": ["Market"], + "assetVolume": 50, + "cashAmount": 10000, + "fundamentalWeight": {"expon": [1.0]}, + "chartWeight": {"expon": [0.0]}, + "noiseWeight": {"expon": [1.0]}, + "noiseScale": 0.001, + "timeWindowSize": [100, 200], + "orderMargin": [0.0, 0.1], + }, + "FCNAgents-1": {"extends": "FCNAgent", "markets": ["SpotMarket-1"]}, + "FCNAgents-2": {"extends": "FCNAgent", "markets": ["SpotMarket-2"]}, + "FCNAgents-I": {"extends": "FCNAgent", "markets": ["IndexMarket-I"]}, + "ArbitrageAgents": { + "class": "ArbitrageAgent", + "numAgents": 100, + "markets": ["IndexMarket-I", "SpotMarket-1", "SpotMarket-2"], + "assetVolume": 50, + "cashAmount": 150000, + "orderVolume": 1, + "orderThresholdPrice": 1.0, + }, + } + runner = cast( + SequentialRunner, + self.test__init__( + setting_mode="dict", logger=None, simulator_class=None, setting=setting + ), + ) + runner._setup() + dummy_order = Order( + agent_id=10, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + with mock.patch( + "pams.agents.fcn_agent.FCNAgent.submit_orders", return_value=[dummy_order] + ): + with pytest.raises(ValueError) + results = runner._collect_orders_from_normal_agents( + session=runner.simulator.sessions[0] + ) From 3edb033477cc5c36d69a135c0f5552a5966725c7 Mon Sep 17 00:00:00 2001 From: Masanori HIRANO Date: Fri, 21 Apr 2023 11:48:53 +0900 Subject: [PATCH 2/5] added test --- tests/pams/runners/test_sequential.py | 56 +++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/tests/pams/runners/test_sequential.py b/tests/pams/runners/test_sequential.py index 59fcc122..015778a4 100644 --- a/tests/pams/runners/test_sequential.py +++ b/tests/pams/runners/test_sequential.py @@ -3,6 +3,7 @@ import random import time from typing import Dict +from typing import List from typing import Type from typing import cast from unittest import mock @@ -11,7 +12,9 @@ from numpy.linalg import LinAlgError from pams import LIMIT_ORDER +from pams import Market from pams import Order +from pams.agents import Agent from pams.runners import Runner from pams.runners import SequentialRunner from tests.pams.runners.test_base import TestRunner @@ -1204,18 +1207,63 @@ def test_collect_orders_from_normal_agents(self) -> None: ), ) runner._setup() + + def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: + return [ + Order( + agent_id=cls.agent_id, + market_id=markets[0].market_id, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + ] + + with mock.patch("pams.agents.fcn_agent.FCNAgent.submit_orders", dummy_fn): + results = runner._collect_orders_from_normal_agents( + session=runner.simulator.sessions[0] + ) + assert len(results) == 3 + dummy_order = Order( - agent_id=10, - market_id=0, + agent_id=100, + market_id=2, is_buy=True, kind=LIMIT_ORDER, volume=1, price=300.0, ) + + with mock.patch( + "pams.agents.fcn_agent.FCNAgent.submit_orders", return_value=[dummy_order] + ): + with pytest.raises(ValueError): + _ = runner._collect_orders_from_normal_agents( + session=runner.simulator.sessions[0] + ) + + setting["simulation"]["sessions"][0]["withOrderPlacement"] = False + runner = cast( + SequentialRunner, + self.test__init__( + setting_mode="dict", logger=None, simulator_class=None, setting=setting + ), + ) + runner._setup() + dummy_order = Order( + agent_id=100, + market_id=2, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + with mock.patch( "pams.agents.fcn_agent.FCNAgent.submit_orders", return_value=[dummy_order] ): - with pytest.raises(ValueError) - results = runner._collect_orders_from_normal_agents( + with pytest.raises(AssertionError): + _ = runner._collect_orders_from_normal_agents( session=runner.simulator.sessions[0] ) From 73ad63555981a0a5c0a15abe246660376e75d954 Mon Sep 17 00:00:00 2001 From: Masanori HIRANO Date: Mon, 24 Apr 2023 01:41:01 +0900 Subject: [PATCH 3/5] added test and bug fix --- pams/order_book.py | 4 +- pams/runners/sequential.py | 4 +- pams/session.py | 2 +- pams/simulator.py | 2 +- tests/pams/runners/test_sequential.py | 340 ++++++++++++++++++++++++++ 5 files changed, 347 insertions(+), 5 deletions(-) diff --git a/pams/order_book.py b/pams/order_book.py index 836b1dc5..8f3413d5 100644 --- a/pams/order_book.py +++ b/pams/order_book.py @@ -79,7 +79,9 @@ def cancel(self, cancel: Cancel) -> None: """ cancel.order.is_canceled = True cancel.placed_at = self.time - self._remove(cancel.order) + if cancel.order in self.priority_queue: + # in case that order is executed before canceling. + self._remove(cancel.order) def get_best_order(self) -> Optional[Order]: """get the order with the highest priority. diff --git a/pams/runners/sequential.py b/pams/runners/sequential.py index 79b64aef..5c05b890 100644 --- a/pams/runners/sequential.py +++ b/pams/runners/sequential.py @@ -457,7 +457,7 @@ def _handle_orders( log_: CancelLog = market._cancel_order(cancel=order) agent = self.simulator.id2agent[order.order.agent_id] agent.canceled_order(log=log_) - self.simulator._trigger_event_after_cancel(cancel_log=order) + self.simulator._trigger_event_after_cancel(cancel_log=log_) else: raise NotImplementedError if session.with_order_execution: @@ -517,7 +517,7 @@ def _handle_orders( log_ = market._cancel_order(cancel=order) agent = self.simulator.id2agent[order.order.agent_id] agent.canceled_order(log=log_) - self.simulator._trigger_event_after_cancel(cancel_log=order) + self.simulator._trigger_event_after_cancel(cancel_log=log_) else: raise NotImplementedError if session.with_order_execution: diff --git a/pams/session.py b/pams/session.py index c454bc16..6d27f85f 100644 --- a/pams/session.py +++ b/pams/session.py @@ -119,7 +119,7 @@ def setup(self, settings: Dict[str, Any], *args, **kwargs) -> None: # type: ign # TODO: check malOrders + maxHighFrequencyOrders >= 1 if "highFrequencySubmitRate" in settings: # TODO: check non-negative - self.max_high_frequency_orders = settings["highFrequencySubmitRate"] + self.high_frequency_submission_rate = settings["highFrequencySubmitRate"] if "hifreqSubmitRate" in settings: raise ValueError( "hifreqSubmitRate is replaced to highFrequencySubmitRate in pams. Please delete it." diff --git a/pams/simulator.py b/pams/simulator.py index 9a8b388e..a993b1c8 100644 --- a/pams/simulator.py +++ b/pams/simulator.py @@ -347,7 +347,7 @@ def _trigger_event_after_cancel(self, cancel_log: "CancelLog") -> None: # type: Returns: None """ - time: int = cancel_log.time + time: int = cancel_log.cancel_time event_hooks = self.events_dict["cancel_after"] target_event_hooks: List[EventHook] = [] if None in event_hooks: diff --git a/tests/pams/runners/test_sequential.py b/tests/pams/runners/test_sequential.py index 015778a4..73a4a77e 100644 --- a/tests/pams/runners/test_sequential.py +++ b/tests/pams/runners/test_sequential.py @@ -5,6 +5,7 @@ from typing import Dict from typing import List from typing import Type +from typing import Union from typing import cast from unittest import mock @@ -12,6 +13,7 @@ from numpy.linalg import LinAlgError from pams import LIMIT_ORDER +from pams import Cancel from pams import Market from pams import Order from pams.agents import Agent @@ -1267,3 +1269,341 @@ def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: _ = runner._collect_orders_from_normal_agents( session=runner.simulator.sessions[0] ) + + def test_handle_orders(self) -> None: + setting = { + "simulation": { + "markets": ["Market"], + "agents": ["FCNAgents"], + "sessions": [ + { + "sessionName": 0, + "iterationSteps": 10, + "withOrderPlacement": True, + "withOrderExecution": True, + "withPrint": True, + } + ], + }, + "Market": {"class": "Market", "tickSize": 0.00001, "marketPrice": 300.0}, + "FCNAgents": { + "class": "FCNAgent", + "numAgents": 10, + "markets": ["Market"], + "assetVolume": 50, + "cashAmount": 10000, + "fundamentalWeight": {"expon": [1.0]}, + "chartWeight": {"expon": [0.0]}, + "noiseWeight": {"expon": [1.0]}, + "meanReversionTime": {"uniform": [50, 100]}, + "noiseScale": 0.001, + "timeWindowSize": [100, 200], + "orderMargin": [0.0, 0.1], + }, + } + runner = cast( + SequentialRunner, + self.test__init__( + setting_mode="dict", logger=None, simulator_class=None, setting=setting + ), + ) + runner._setup() + runner.simulator.markets[0]._update_time(next_fundamental_price=200.0) + local_orders = runner._collect_orders_from_normal_agents( + session=runner.simulator.sessions[0] + ) + runner.simulator.sessions[0].with_order_placement = False + with pytest.raises(AssertionError): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + runner = cast( + SequentialRunner, + self.test__init__( + setting_mode="dict", logger=None, simulator_class=None, setting=setting + ), + ) + runner._setup() + runner.simulator.markets[0]._update_time(next_fundamental_price=200.0) + dummy_order = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_cancel = Cancel(order=dummy_order) + local_orders = [[dummy_order], [dummy_cancel]] + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + class BuggyOrder: + def __init__(self, market_id: int = 0, agent_id: int = 0): + self.market_id = market_id + self.agent_id = agent_id + + local_orders = [[dummy_order], [dummy_cancel], [BuggyOrder()]] + with pytest.raises(NotImplementedError): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + dummy_order1 = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_order2 = Order( + agent_id=0, + market_id=0, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + runner.simulator.markets[0]._is_running = True + local_orders = [[dummy_order1], [dummy_order2]] + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + setting = { + "simulation": { + "markets": ["SpotMarket-1", "SpotMarket-2", "IndexMarket-I"], + "agents": [ + "FCNAgents-1", + "FCNAgents-2", + "FCNAgents-I", + "ArbitrageAgents", + ], + "sessions": [ + { + "sessionName": 0, + "iterationSteps": 100, + "withOrderPlacement": True, + "withOrderExecution": True, + "withPrint": True, + "maxNormalOrders": 3, + "MEMO": "The same number as #markets", + "maxHighFrequencyOrders": 0, + "highFrequencySubmitRate": 0.0, + } + ], + }, + "SpotMarket": { + "class": "Market", + "tickSize": 0.00001, + "marketPrice": 300.0, + "outstandingShares": 25000, + }, + "SpotMarket-1": {"extends": "SpotMarket"}, + "SpotMarket-2": {"extends": "SpotMarket"}, + "IndexMarket-I": { + "class": "IndexMarket", + "tickSize": 0.00001, + "marketPrice": 300.0, + "outstandingShares": 25000, + "markets": ["SpotMarket-1", "SpotMarket-2"], + }, + "FCNAgent": { + "class": "FCNAgent", + "numAgents": 100, + "markets": ["Market"], + "assetVolume": 50, + "cashAmount": 10000, + "fundamentalWeight": {"expon": [1.0]}, + "chartWeight": {"expon": [0.0]}, + "noiseWeight": {"expon": [1.0]}, + "noiseScale": 0.001, + "timeWindowSize": [100, 200], + "orderMargin": [0.0, 0.1], + }, + "FCNAgents-1": {"extends": "FCNAgent", "markets": ["SpotMarket-1"]}, + "FCNAgents-2": {"extends": "FCNAgent", "markets": ["SpotMarket-2"]}, + "FCNAgents-I": {"extends": "FCNAgent", "markets": ["IndexMarket-I"]}, + "ArbitrageAgents": { + "class": "ArbitrageAgent", + "numAgents": 100, + "markets": ["IndexMarket-I", "SpotMarket-1", "SpotMarket-2"], + "assetVolume": 50, + "cashAmount": 150000, + "orderVolume": 1, + "orderThresholdPrice": 1.0, + }, + } + runner = cast( + SequentialRunner, + self.test__init__( + setting_mode="dict", logger=None, simulator_class=None, setting=setting + ), + ) + runner._setup() + runner.simulator.markets[0]._is_running = True + runner.simulator.markets[1]._is_running = True + runner.simulator.markets[2]._is_running = True + runner.simulator.markets[0]._update_time(next_fundamental_price=200.0) + runner.simulator.markets[1]._update_time(next_fundamental_price=200.0) + runner.simulator.markets[2]._update_time(next_fundamental_price=200.0) + local_orders = runner._collect_orders_from_normal_agents( + session=runner.simulator.sessions[0] + ) + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + dummy_order1 = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_order2 = Order( + agent_id=0, + market_id=0, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + local_orders = [[dummy_order1], [dummy_order2]] + runner.simulator.sessions[0].high_frequency_submission_rate = 1.0 + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + runner.simulator.sessions[0].max_high_frequency_orders = 3 + dummy_order1 = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_order2 = Order( + agent_id=0, + market_id=0, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + local_orders = [[dummy_order1], [dummy_order2]] + + def dummy_fn(cls: Agent, markets: List[Market]) -> List[Union[Order, Cancel]]: + d_order = Order( + agent_id=cls.agent_id, + market_id=markets[0].market_id, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + d_order2 = Order( + agent_id=cls.agent_id, + market_id=markets[0].market_id, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + d_cancel = Cancel(order=d_order) + return [d_order, d_order2, d_cancel] + + with mock.patch( + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn + ): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + def dummy_fn2(cls: Agent, markets: List[Market]) -> List[Order]: + return [ + Order( + agent_id=cls.agent_id + 1, + market_id=markets[0].market_id, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + ] + + dummy_order1 = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_order2 = Order( + agent_id=0, + market_id=0, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + local_orders = [[dummy_order1], [dummy_order2]] + with mock.patch( + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn2 + ): + with pytest.raises(ValueError): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: + d_order = Order( + agent_id=cls.agent_id, + market_id=markets[0].market_id, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=300.0, + ) + d_cancel = Cancel(order=d_order) + d_bug = BuggyOrder(market_id=markets[0].market_id, agent_id=cls.agent_id) + return [d_order, d_cancel, d_bug] + + dummy_order1 = Order( + agent_id=0, + market_id=0, + is_buy=True, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + dummy_order2 = Order( + agent_id=0, + market_id=0, + is_buy=False, + kind=LIMIT_ORDER, + volume=1, + price=100.0, + ) + local_orders = [[dummy_order1], [dummy_order2]] + with mock.patch( + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn + ): + with pytest.raises(NotImplementedError): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) + + runner.simulator.sessions[0].with_order_placement = False + local_orders = [[], []] + with mock.patch( + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn + ): + with pytest.raises(AssertionError): + runner._handle_orders( + session=runner.simulator.sessions[0], local_orders=local_orders + ) From eba15112ad74d9e9e4f5b8c03ae3fccdda43cf6c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 23 Apr 2023 16:42:16 +0000 Subject: [PATCH 4/5] Bumping version from 0.0.14 to 0.0.15 --- pams/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pams/version.py b/pams/version.py index 311f216e..6561790f 100644 --- a/pams/version.py +++ b/pams/version.py @@ -1 +1 @@ -__version__ = "0.0.14" +__version__ = "0.0.15" diff --git a/pyproject.toml b/pyproject.toml index ef96b1fd..1211bc1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pams" -version = "0.0.14" +version = "0.0.15" description = "PAMS: Platform for Artificial Market Simulations" authors = ["Masanori HIRANO "] license = "MIT" From fe3cae25373ffda5579b0126f821c49360c2ade9 Mon Sep 17 00:00:00 2001 From: Masanori HIRANO Date: Mon, 24 Apr 2023 01:46:35 +0900 Subject: [PATCH 5/5] fix typing issues --- tests/pams/runners/test_sequential.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/pams/runners/test_sequential.py b/tests/pams/runners/test_sequential.py index 73a4a77e..b3d68926 100644 --- a/tests/pams/runners/test_sequential.py +++ b/tests/pams/runners/test_sequential.py @@ -1245,7 +1245,7 @@ def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: session=runner.simulator.sessions[0] ) - setting["simulation"]["sessions"][0]["withOrderPlacement"] = False + setting["simulation"]["sessions"][0]["withOrderPlacement"] = False # type: ignore runner = cast( SequentialRunner, self.test__init__( @@ -1345,7 +1345,7 @@ def __init__(self, market_id: int = 0, agent_id: int = 0): self.market_id = market_id self.agent_id = agent_id - local_orders = [[dummy_order], [dummy_cancel], [BuggyOrder()]] + local_orders = [[dummy_order], [dummy_cancel], [BuggyOrder()]] # type: ignore with pytest.raises(NotImplementedError): runner._handle_orders( session=runner.simulator.sessions[0], local_orders=local_orders @@ -1560,7 +1560,7 @@ def dummy_fn2(cls: Agent, markets: List[Market]) -> List[Order]: session=runner.simulator.sessions[0], local_orders=local_orders ) - def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: + def dummy_fn3(cls: Agent, markets: List[Market]) -> List[Order]: d_order = Order( agent_id=cls.agent_id, market_id=markets[0].market_id, @@ -1571,7 +1571,7 @@ def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: ) d_cancel = Cancel(order=d_order) d_bug = BuggyOrder(market_id=markets[0].market_id, agent_id=cls.agent_id) - return [d_order, d_cancel, d_bug] + return [d_order, d_cancel, d_bug] # type: ignore dummy_order1 = Order( agent_id=0, @@ -1591,7 +1591,7 @@ def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: ) local_orders = [[dummy_order1], [dummy_order2]] with mock.patch( - "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn3 ): with pytest.raises(NotImplementedError): runner._handle_orders( @@ -1601,7 +1601,7 @@ def dummy_fn(cls: Agent, markets: List[Market]) -> List[Order]: runner.simulator.sessions[0].with_order_placement = False local_orders = [[], []] with mock.patch( - "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn + "pams.agents.arbitrage_agent.ArbitrageAgent.submit_orders", dummy_fn3 ): with pytest.raises(AssertionError): runner._handle_orders(