diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index a68a17e38..7c014575d 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -5,7 +5,7 @@ name: Python "on": pull_request: branches: - - main + - develop jobs: diff --git a/Makefile b/Makefile index dd0d4822e..c2f91466d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -VEGA_TAG := 607a5b1 -WALLET_TAG := cb58876 -DATA_NODE_TAG := 3d8887d -CONSOLE_TAG := d4f0d62 -PROTO_TAG := f303ea3 +VEGA_TAG := develop +WALLET_TAG := develop +DATA_NODE_TAG := develop +CONSOLE_TAG := master +PROTO_TAG := develop EXTERN_DIR := "./extern" all: pull_deps build_deps @@ -93,4 +93,10 @@ flake8: test: @pipenv --bare install --dev # 1>/dev/null 2>&1 @pipenv run pip install -e . - @env PYTHONPATH=. pipenv run pytest tests/ + @env PYTHONPATH=. pipenv run pytest -m "not integration" tests/ + +.PHONY: test_integration +test_integration: + @pipenv --bare install --dev # 1>/dev/null 2>&1 + @pipenv run pip install -e . + @env PYTHONPATH=. pipenv run pytest -m integration tests/ diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 000000000..b916fe351 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + integration: mark a test as requiring a full vega sim infrastructure with running backend \ No newline at end of file diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/test_trading.py b/tests/integration/test_trading.py new file mode 100644 index 000000000..8e1416b60 --- /dev/null +++ b/tests/integration/test_trading.py @@ -0,0 +1,95 @@ +import pytest + +from tests.integration.utils.fixtures import ( + vega_service_with_market, + vega_service, + create_and_faucet_wallet, + WalletConfig, +) +from vega_sim.null_service import VegaServiceNull +import vega_sim.proto.vega as vega_protos + + +LIQ = WalletConfig("liq", "liq") + + +@pytest.mark.integration +def test_submit_amend_liquidity(vega_service_with_market: VegaServiceNull): + vega = vega_service_with_market + market_id = vega.all_markets()[0].id + + create_and_faucet_wallet(vega=vega, wallet=LIQ) + vega.submit_liquidity( + LIQ.name, + market_id=market_id, + commitment_amount=100, + fee=0.001, + buy_specs=[("PEGGED_REFERENCE_MID", 0.5, 1)], + sell_specs=[("PEGGED_REFERENCE_MID", 0.5, 1)], + is_amendment=False, + ) + vega.forward("1s") + + liq_provis = vega.party_liquidity_provisions(LIQ.name, market_id=market_id) + + assert len(liq_provis) == 1 + + for provis in [ + liq_provis[0].sells[0].liquidity_order, + liq_provis[0].buys[0].liquidity_order, + ]: + assert provis.reference == vega_protos.vega.PeggedReference.PEGGED_REFERENCE_MID + assert provis.offset == "50000" + assert provis.proportion == 1 + + buy_specs = [ + vega_protos.vega.LiquidityOrder( + reference=vega_protos.vega.PeggedReference.PEGGED_REFERENCE_MID, + offset="100000", + proportion=2, + ), + vega_protos.vega.LiquidityOrder( + reference=vega_protos.vega.PeggedReference.PEGGED_REFERENCE_BEST_BID, + offset="500000", + proportion=5, + ), + ] + sell_specs = [ + vega_protos.vega.LiquidityOrder( + reference=vega_protos.vega.PeggedReference.PEGGED_REFERENCE_MID, + offset="500000", + proportion=6, + ), + vega_protos.vega.LiquidityOrder( + reference=vega_protos.vega.PeggedReference.PEGGED_REFERENCE_BEST_ASK, + offset="20000", + proportion=1, + ), + ] + vega.submit_liquidity( + LIQ.name, + market_id=market_id, + commitment_amount=200, + fee=0.005, + buy_specs=[("PEGGED_REFERENCE_MID", 1, 2), ("PEGGED_REFERENCE_BEST_BID", 5, 5)], + sell_specs=[ + ("PEGGED_REFERENCE_MID", 5, 6), + ("PEGGED_REFERENCE_BEST_ASK", 0.2, 1), + ], + is_amendment=True, + ) + + vega.forward("1s") + liq_provis = vega.party_liquidity_provisions(LIQ.name, market_id=market_id) + + assert len(liq_provis) == 1 + + for provis, exp_provis in zip(liq_provis[0].sells, sell_specs): + assert provis.liquidity_order.reference == exp_provis.reference + assert provis.liquidity_order.offset == exp_provis.offset + assert provis.liquidity_order.proportion == exp_provis.proportion + + for provis, exp_provis in zip(liq_provis[0].buys, buy_specs): + assert provis.liquidity_order.reference == exp_provis.reference + assert provis.liquidity_order.offset == exp_provis.offset + assert provis.liquidity_order.proportion == exp_provis.proportion diff --git a/tests/integration/utils/__init__.py b/tests/integration/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/utils/fixtures.py b/tests/integration/utils/fixtures.py new file mode 100644 index 000000000..d54da3780 --- /dev/null +++ b/tests/integration/utils/fixtures.py @@ -0,0 +1,128 @@ +import pytest +from collections import namedtuple + +from vega_sim.null_service import VegaServiceNull + +WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"]) + +MM_WALLET = WalletConfig("mm", "pin") + +AUCTION1 = WalletConfig("auction1", "auction1") +AUCTION2 = WalletConfig("auction2", "auction2") + +TERMINATE_WALLET = WalletConfig("TERMINATE", "TERMINATE") + +TRADER_WALLET = WalletConfig("TRADER", "TRADER") + +ASSET_NAME = "tDAI" + +WALLETS = [MM_WALLET, AUCTION1, AUCTION2, TERMINATE_WALLET, TRADER_WALLET] + + +def create_and_faucet_wallet( + vega: VegaServiceNull, wallet: WalletConfig, amount: float = 1e4 +): + asset_id = vega.find_asset_id(symbol=ASSET_NAME) + vega.create_wallet(wallet.name, wallet.passphrase) + vega.mint(wallet.name, asset_id, amount) + + +def build_basic_market(vega: VegaServiceNull): + for wallet in WALLETS: + vega.create_wallet(wallet.name, wallet.passphrase) + + vega.mint( + MM_WALLET.name, + asset="VOTE", + amount=1e4, + ) + vega.forward("10s") + + # Create asset + vega.create_asset( + MM_WALLET.name, + name=ASSET_NAME, + symbol=ASSET_NAME, + decimals=5, + max_faucet_amount=1e10, + ) + vega.forward("10s") + vega.wait_for_datanode_sync() + + asset_id = vega.find_asset_id(symbol=ASSET_NAME) + + for wallet in WALLETS: + vega.mint( + wallet.name, + asset=asset_id, + amount=10000, + ) + vega.forward("10s") + vega.create_simple_market( + market_name="CRYPTO:BTCDAI/DEC22", + proposal_wallet=MM_WALLET.name, + settlement_asset_id=asset_id, + termination_wallet=TERMINATE_WALLET.name, + market_decimals=5, + liquidity_commitment=vega.build_new_market_liquidity_commitment( + asset_id=asset_id, + commitment_amount=100, + fee=0.002, + buy_specs=[("PEGGED_REFERENCE_MID", 0.0005, 1)], + sell_specs=[("PEGGED_REFERENCE_MID", 0.0005, 1)], + market_decimals=5, + ), + ) + market_id = vega.all_markets()[0].id + + # Add transactions in the proposed market to pass opening auction at price 0.3 + vega.submit_order( + trading_wallet=AUCTION1.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + volume=1, + price=0.3, + ) + + vega.submit_order( + trading_wallet=AUCTION2.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_SELL", + volume=1, + price=0.3, + ) + + vega.submit_order( + trading_wallet=TRADER_WALLET.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_BUY", + volume=1, + price=0.29998, + ) + vega.submit_order( + trading_wallet=TRADER_WALLET.name, + market_id=market_id, + order_type="TYPE_LIMIT", + time_in_force="TIME_IN_FORCE_GTC", + side="SIDE_SELL", + volume=1, + price=0.30002, + ) + + +@pytest.fixture +def vega_service(): + with VegaServiceNull(warn_on_raw_data_access=False, run_with_console=False) as vega: + yield vega + + +@pytest.fixture +def vega_service_with_market(vega_service): + build_basic_market(vega_service) + return vega_service diff --git a/tests/vega_sim/api/test_data_raw.py b/tests/vega_sim/api/test_data_raw.py index 949b36880..ba470e92d 100644 --- a/tests/vega_sim/api/test_data_raw.py +++ b/tests/vega_sim/api/test_data_raw.py @@ -14,6 +14,7 @@ all_markets, asset_info, infrastructure_fee_accounts, + liquidity_provisions, market_accounts, market_data, market_info, @@ -348,3 +349,26 @@ def OrderByReference(self, request, context): res = order_status_by_reference(reference="foo", data_client=data_client) assert res == expected + + +def test_liquidity_provisions(trading_data_servicer_and_port): + def LiquidityProvisions(self, request, context): + return data_node_protos.trading_data.LiquidityProvisionsResponse( + liquidity_provisions=[ + vega_protos.vega.LiquidityProvision( + market_id=request.market, party_id=request.party + ) + ] + ) + + server, port, mock_servicer = trading_data_servicer_and_port + mock_servicer.LiquidityProvisions = LiquidityProvisions + + add_TradingDataServiceServicer_to_server(mock_servicer(), server) + + data_client = VegaTradingDataClient(f"localhost:{port}") + res = liquidity_provisions( + market_id="MARKET", party_id="PARTY", data_client=data_client + ) + + assert res[0].market_id == "MARKET" diff --git a/vega_sim/api/data_raw.py b/vega_sim/api/data_raw.py index 6ad0364ad..aeb2849c6 100644 --- a/vega_sim/api/data_raw.py +++ b/vega_sim/api/data_raw.py @@ -179,3 +179,28 @@ def market_depth( market_id=market_id, max_depth=max_depth ) ) + + +def liquidity_provisions( + data_client: vac.VegaTradingDataClient, + market_id: Optional[str] = None, + party_id: Optional[str] = None, +) -> Optional[List[vega_protos.vega.LiquidityProvision]]: + """Loads the current liquidity provision(s) for a given market and/or party. + + Args: + data_client: + VegaTradingDataClient, an instantiated gRPC trading data client + market_id: + Optional[str], the ID of the market from which to pull liquidity provisions + party_id: + Optional[str], the ID of the party from which to pull liquidity provisions + + Returns: + List[LiquidityProvision], list of liquidity provisions (if any exist) + """ + return data_client.LiquidityProvisions( + data_node_protos.trading_data.LiquidityProvisionsRequest( + market=market_id, party=party_id + ) + ).liquidity_provisions diff --git a/vega_sim/service.py b/vega_sim/service.py index 655d5f4e8..4a17f178c 100644 --- a/vega_sim/service.py +++ b/vega_sim/service.py @@ -873,8 +873,8 @@ def submit_liquidity( market_id: str, commitment_amount: float, fee: float, - buy_specs: List[Tuple[str, int, int]], - sell_specs: List[Tuple[str, int, int]], + buy_specs: List[Tuple[str, float, int]], + sell_specs: List[Tuple[str, float, int]], is_amendment: bool = False, ): """Submit/Amend a custom liquidity profile. @@ -992,3 +992,48 @@ def order_status_by_reference( price_decimals=self.market_price_decimals[market_id], position_decimals=self.market_pos_decimals[market_id], ) + + @raw_data + def liquidity_provisions( + self, + market_id: Optional[str] = None, + party_id: Optional[str] = None, + ) -> Optional[List[vega_protos.vega.LiquidityProvision]]: + """Loads the current liquidity provision(s) for a given market and/or party. + + Args: + market_id: + Optional[str], the ID of the market from which to + pull liquidity provisions + party_id: + Optional[str], the ID of the party from which to + pull liquidity provisions + + Returns: + List[LiquidityProvision], list of liquidity provisions (if any exist) + """ + return data_raw.liquidity_provisions( + self.trading_data_client, market_id=market_id, party_id=party_id + ) + + def party_liquidity_provisions( + self, + wallet_name: str, + market_id: Optional[str] = None, + ) -> Optional[List[vega_protos.vega.LiquidityProvision]]: + """Loads the current liquidity provision(s) for a given market and/or party. + + Args: + market_id: + Optional[str], the ID of the market from which to + pull liquidity provisions + party_id: + Optional[str], the ID of the party from which to + pull liquidity provisions + + Returns: + List[LiquidityProvision], list of liquidity provisions (if any exist) + """ + return self.liquidity_provisions( + market_id=market_id, party_id=self.wallet.public_key(wallet_name) + )