diff --git a/tests/integration/test_trading.py b/tests/integration/test_trading.py index 02e028c66..6a335b97e 100644 --- a/tests/integration/test_trading.py +++ b/tests/integration/test_trading.py @@ -403,6 +403,123 @@ def test_funding_reward_pool(vega_service_with_market: VegaServiceNull): assert party_a_accounts_t2[0].balance == 799.8 +@pytest.mark.integration +def test_iceberg_order(vega_service_with_market: VegaServiceNull): + vega = vega_service_with_market + vega.wait_for_total_catchup() + + create_and_faucet_wallet(vega=vega, wallet=PARTY_A, amount=1e5) + create_and_faucet_wallet(vega=vega, wallet=PARTY_B, amount=1e5) + create_and_faucet_wallet(vega=vega, wallet=PARTY_C, amount=1e5) + vega.wait_for_total_catchup() + + market_id = vega.all_markets()[0].id + + vega.submit_liquidity( + MM_WALLET.name, + market_id=market_id, + commitment_amount=100, + fee=0.001, + buy_specs=[("PEGGED_REFERENCE_BEST_BID", 0.1, 1)], + sell_specs=[("PEGGED_REFERENCE_BEST_ASK", 0.1, 1)], + is_amendment=True, + ) + + with pytest.raises(ValueError): + vega.submit_order( + trading_key=PARTY_A.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + price=0.29, + volume=10, + peak_size=5, + ) + with pytest.raises(ValueError): + vega.submit_order( + trading_key=PARTY_A.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + price=0.29, + volume=10, + minimum_visible_size=2, + ) + + # Place icebergs orders + vega.submit_order( + trading_key=PARTY_A.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + price=0.29, + volume=10, + peak_size=5, + minimum_visible_size=2, + ) + vega.submit_order( + trading_key=PARTY_A.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_SELL", + price=0.31, + volume=10, + peak_size=5, + minimum_visible_size=2, + ) + + # Place limit order at same price levels + vega.submit_order( + trading_key=PARTY_B.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + price=0.29, + volume=1000, + ) + vega.submit_order( + trading_key=PARTY_B.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_SELL", + price=0.31, + volume=1000, + ) + vega.wait_for_total_catchup() + + # Place market orders and check only the displayed volume is filled + vega.submit_market_order( + trading_key=PARTY_C.name, + market_id=market_id, + fill_or_kill=False, + side="SIDE_SELL", + volume=10, + ) + vega.wait_for_total_catchup() + + position = vega.positions_by_market(key_name=PARTY_A.name, market_id=market_id) + assert position.open_volume == 5 + + # Place market orders and check only the displayed volume is filled + vega.submit_market_order( + trading_key=PARTY_C.name, + market_id=market_id, + fill_or_kill=False, + side="SIDE_BUY", + volume=10, + ) + vega.wait_for_total_catchup() + + position = vega.positions_by_market(key_name=PARTY_A.name, market_id=market_id) + assert position.open_volume == 0 + + @pytest.mark.integration def test_liquidation_price_witin_estimate_position_bounds_AC002( vega_service: VegaServiceNull, diff --git a/vega_sim/api/trading.py b/vega_sim/api/trading.py index 6a68941e2..e4f98f2a9 100644 --- a/vega_sim/api/trading.py +++ b/vega_sim/api/trading.py @@ -53,6 +53,7 @@ def submit_order( key_name: Optional[str] = None, reduce_only: bool = False, post_only: bool = False, + iceberg_opts: Optional[vega_protos.commands.IcebergOpts] = None, ) -> Optional[str]: """ Submit orders as specified to required pre-existing market. @@ -103,6 +104,8 @@ def submit_order( bool, whether the order should only reduce a parties position. post_only: bool, whether an order should be prevented from trading immediately. + iceberg_ops: + Optional[vega_protos.commands.IcebergOpts], options to make order an iceberg order Returns: Optional[str], Order ID if wait is True, otherwise None @@ -121,6 +124,7 @@ def submit_order( pegged_order=pegged_order, reduce_only=reduce_only, post_only=post_only, + iceberg_opts=iceberg_opts, ) # Sign the transaction with an order submission command @@ -186,6 +190,7 @@ def amend_order( volume_delta: float = 0, time_in_force: Optional[Union[vega_protos.vega.Order.TimeInForce, str]] = None, key_name: Optional[str] = None, + iceberg_opts: Optional[vega_protos.commands.v1.IcebergOpts] = None, ): """ Amend a Limit order by orderID in the specified market @@ -225,6 +230,7 @@ def amend_order( time_in_force=time_in_force, pegged_offset=pegged_offset, pegged_reference=pegged_reference, + iceberg_opts=iceberg_opts, ) wallet.submit_transaction( @@ -426,6 +432,7 @@ def order_amendment( time_in_force: Optional[vega_protos.vega.Order.TimeInForce] = None, pegged_offset: Optional[str] = None, pegged_reference: Optional[vega_protos.vega.PeggedReference] = None, + iceberg_opts: Optional[vega_protos.commands.v1.IcebergOpts] = None, ) -> OrderAmendment: """Creates a Vega OrderAmendment object. @@ -519,6 +526,7 @@ def order_submission( pegged_order: Optional[Union[vega_protos.PeggedOrder, str]] = None, reduce_only: bool = False, post_only: bool = False, + iceberg_opts: Optional[vega_protos.commands.v1.IcebergOpts] = None, ) -> OrderSubmission: """Creates a Vega OrderSubmission object. @@ -579,6 +587,7 @@ def order_submission( type=order_type, reduce_only=reduce_only, post_only=post_only, + iceberg_opts=iceberg_opts, ) # Update OrderSubmission object with optional fields if specified @@ -592,6 +601,8 @@ def order_submission( if pegged_order is not None: command.pegged_order.CopyFrom(pegged_order) + if iceberg_opts is not None: + command.iceberg_opts.CopyFrom(iceberg_opts) # Return the created and updated OrderSubmission object return command diff --git a/vega_sim/network_service.py b/vega_sim/network_service.py index a8d865fad..c0052bc81 100644 --- a/vega_sim/network_service.py +++ b/vega_sim/network_service.py @@ -153,10 +153,10 @@ def manage_vega_processes( vega_console_path, "nx", "serve", - "--port", - f"{vega_console_port}", "-o", "trading", + "--port", + f"{vega_console_port}", ], dir_root=tmp_vega_dir, log_name="console", diff --git a/vega_sim/null_service.py b/vega_sim/null_service.py index 6dfd06581..045e644bc 100644 --- a/vega_sim/null_service.py +++ b/vega_sim/null_service.py @@ -529,10 +529,10 @@ def manage_vega_processes( vega_console_path, "nx", "serve", - "--port", - f"{port_config[Ports.CONSOLE]}", "-o", "trading", + "--port", + f"{port_config[Ports.CONSOLE]}", ], dir_root=tmp_vega_dir, log_name="console", diff --git a/vega_sim/service.py b/vega_sim/service.py index cff3e77ad..7f99208d2 100644 --- a/vega_sim/service.py +++ b/vega_sim/service.py @@ -719,6 +719,8 @@ def submit_order( trading_wallet: Optional[str] = None, reduce_only: bool = False, post_only: bool = False, + peak_size: Optional[float] = None, + minimum_visible_size: Optional[float] = None, ) -> Optional[str]: """ Submit orders as specified to required pre-existing market. @@ -762,6 +764,10 @@ def submit_order( post_only (bool): Whether order should be prevented from trading immediately. Defaults to False. + peak_size: + optional float, size of the order that is made visible and can be traded with during the execution of a single order. + minimum_visible_size: + optional float, minimum allowed remaining size of the order before it is replenished back to its peak size Returns: Optional[str], If order acceptance is waited for, returns order ID. @@ -794,6 +800,12 @@ def submit_order( else: logger.debug(msg) return + if (peak_size is None and minimum_visible_size is not None) or ( + peak_size is not None and minimum_visible_size is None + ): + raise ValueError( + "Both 'peak_size' and 'minimum_visible_size' must be specified or none at all." + ) return trading.submit_order( wallet=self.wallet, @@ -824,6 +836,16 @@ def submit_order( key_name=trading_key, reduce_only=reduce_only, post_only=post_only, + iceberg_opts=vega_protos.commands.v1.commands.IcebergOpts( + peak_size=num_to_padded_int( + peak_size, self.market_pos_decimals[market_id] + ), + minimum_visible_size=num_to_padded_int( + minimum_visible_size, self.market_pos_decimals[market_id] + ), + ) + if (peak_size is not None and minimum_visible_size is not None) + else None, ) def get_blockchain_time(self, in_seconds: bool = False) -> int: