diff --git a/v4-client-py/examples/README.md b/v4-client-py/examples/README.md new file mode 100644 index 00000000..aa010d2e --- /dev/null +++ b/v4-client-py/examples/README.md @@ -0,0 +1,32 @@ +# User guide to test examples + +1. Go to your repository location for the Python client +``` +cd ~/.../v4-clients/v4-client-py +``` +2. Create a virtual environment for the DyDx client, activate it and install requirements +``` +python3 -m venv venv +source venv/bin/activate +pip3 install -r requirements.txt +``` +3. Export PYTHONPATH for your current location +``` +export PYTHONPATH='~/.../v4-clients/v4-client-py' +``` + +Now you are ready to use the examples in this folder. + +# Set up your configurations in constants.py +~/.../v4-clients/v4-client-py/v4_client_py/clients/constants.py + +``` +VALIDATOR_GRPC_ENDPOINT = <> +AERIAL_CONFIG_URL = <> +AERIAL_GRPC_OR_REST_PREFIX = <> +INDEXER_REST_ENDPOINT = <> +INDEXER_WS_ENDPOINT = <> +CHAIN_ID = <> +ENV = <> +``` + diff --git a/v4-client-py/examples/account_endpoints.py b/v4-client-py/examples/account_endpoints.py index 6dc80828..5fb417cd 100644 --- a/v4-client-py/examples/account_endpoints.py +++ b/v4-client-py/examples/account_endpoints.py @@ -1,7 +1,7 @@ -'''Example for placing, replacing, and canceling orders. +"""Example for placing, replacing, and canceling orders. Usage: python -m examples.private_endpoints -''' +""" from v4_client_py.clients import IndexerClient, Subaccount from v4_client_py.clients.constants import Network @@ -9,114 +9,112 @@ from tests.constants import DYDX_TEST_MNEMONIC client = IndexerClient( - config=Network.testnet().indexer_config, + config=Network.config_network().indexer_config, ) try: subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) address = subaccount.address - # Get subaccounts try: subaccounts_response = client.account.get_subaccounts(address) - print(f'{subaccounts_response.data}') - subaccounts = subaccounts_response.data['subaccounts'] + print(f"{subaccounts_response.data}") + subaccounts = subaccounts_response.data["subaccounts"] subaccount_0 = subaccounts[0] - print(f'{subaccount_0}') - subaccount_0_subaccountNumber = subaccount_0['subaccountNumber'] + print(f"{subaccount_0}") + subaccount_0_subaccountNumber = subaccount_0["subaccountNumber"] except: - print('failed to get subaccounts') + print("failed to get subaccounts") try: subaccount_response = client.account.get_subaccount(address, 0) - print(f'{subaccount_response.data}') - subaccount = subaccount_response.data['subaccount'] - print(f'{subaccount}') - subaccount_subaccountNumber = subaccount['subaccountNumber'] + print(f"{subaccount_response.data}") + subaccount = subaccount_response.data["subaccount"] + print(f"{subaccount}") + subaccount_subaccountNumber = subaccount["subaccountNumber"] except: - print('failed to get subaccount') + print("failed to get subaccount") # Get positions try: asset_positions_response = client.account.get_subaccount_asset_positions(address, 0) - print(f'{asset_positions_response.data}') - asset_positions = asset_positions_response.data['positions'] + print(f"{asset_positions_response.data}") + asset_positions = asset_positions_response.data["positions"] if len(asset_positions) > 0: asset_positions_0 = asset_positions[0] - print(f'{asset_positions_0}') + print(f"{asset_positions_0}") except: - print('failed to get asset positions') + print("failed to get asset positions") try: perpetual_positions_response = client.account.get_subaccount_perpetual_positions(address, 0) - print(f'{perpetual_positions_response.data}') - perpetual_positions = perpetual_positions_response.data['positions'] + print(f"{perpetual_positions_response.data}") + perpetual_positions = perpetual_positions_response.data["positions"] if len(perpetual_positions) > 0: perpetual_positions_0 = perpetual_positions[0] - print(f'{perpetual_positions_0}') + print(f"{perpetual_positions_0}") except: - print('failed to get perpetual positions') + print("failed to get perpetual positions") # Get transfers try: transfers_response = client.account.get_subaccount_transfers(address, 0) - print(f'{transfers_response.data}') - transfers = transfers_response.data['transfers'] + print(f"{transfers_response.data}") + transfers = transfers_response.data["transfers"] if len(transfers) > 0: transfers_0 = transfers[0] - print(f'{transfers_0}') + print(f"{transfers_0}") except: - print('failed to get transfers') + print("failed to get transfers") # Get orders try: orders_response = client.account.get_subaccount_orders(address, 0) - print(f'{orders_response.data}') + print(f"{orders_response.data}") orders = orders_response.data if len(orders) > 0: order_0 = orders[0] - print(f'{order_0}') - order_0_id = order_0['id'] + print(f"{order_0}") + order_0_id = order_0["id"] order_response = client.account.get_order(order_id=order_0_id) order = order_response.data - order_id = order['id'] + order_id = order["id"] except: - print('failed to get orders') - + print("failed to get orders") # Get fills try: fills_response = client.account.get_subaccount_fills(address, 0) - print(f'{fills_response.data}') - fills = fills_response.data['fills'] + print(f"{fills_response.data}") + fills = fills_response.data["fills"] if len(fills) > 0: fill_0 = fills[0] - print(f'{fill_0}') + print(f"{fill_0}") except: - print('failed to get fills') + print("failed to get fills") # Get funding try: funding_response = client.account.get_subaccount_funding(address, 0) - print(f'{funding_response.data}') - funding = funding_response.data['fundingPayments'] + print(f"{funding_response.data}") + funding = funding_response.data["fundingPayments"] if len(funding) > 0: funding_0 = funding[0] - print(f'{funding_0}') + print(f"{funding_0}") except: - print('failed to get funding') + print("failed to get funding") # Get historical pnl try: historical_pnl_response = client.account.get_subaccount_historical_pnls(address, 0) - print(f'{historical_pnl_response.data}') - historical_pnl = historical_pnl_response.data['historicalPnl'] + print(f"{historical_pnl_response.data}") + historical_pnl = historical_pnl_response.data["historicalPnl"] if len(historical_pnl) > 0: historical_pnl_0 = historical_pnl[0] - print(f'{historical_pnl_0}') + print(f"{historical_pnl_0}") except: - print('failed to get historical pnl') + print("failed to get historical pnl") except: - print('from_mnemonic failed') \ No newline at end of file + print("from_mnemonic failed") diff --git a/v4-client-py/examples/chain_client/Account.py b/v4-client-py/examples/chain_client/Account.py deleted file mode 100644 index 2dc29c35..00000000 --- a/v4-client-py/examples/chain_client/Account.py +++ /dev/null @@ -1,21 +0,0 @@ -import asyncio -import logging - -from v4_client_py.clients import ValidatorClient, Subaccount -from v4_client_py.clients.constants import Network - -from tests.constants import DYDX_TEST_MNEMONIC - -client = ValidatorClient( - config=Network.testnet().validator_config, -) -subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) -address = subaccount.address - -async def main() -> None: - acc = client.get.account(address=address) - print(acc) - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/chain_client/BankBalance.py b/v4-client-py/examples/chain_client/BankBalance.py deleted file mode 100644 index 17f558ed..00000000 --- a/v4-client-py/examples/chain_client/BankBalance.py +++ /dev/null @@ -1,23 +0,0 @@ -import asyncio -import logging - - -from v4_client_py.clients import ValidatorClient, Subaccount -from v4_client_py.clients.constants import Network - -from tests.constants import DYDX_TEST_MNEMONIC - -client = ValidatorClient( - config=Network.testnet().validator_config, -) -subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) -address = subaccount.address - -async def main() -> None: - denom = "USDC" - bank_balance = await client.get.bank_balance(address=address, denom=denom) - print(bank_balance) - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file diff --git a/v4-client-py/examples/chain_client/BankBalances.py b/v4-client-py/examples/chain_client/BankBalances.py deleted file mode 100644 index 6605d0f2..00000000 --- a/v4-client-py/examples/chain_client/BankBalances.py +++ /dev/null @@ -1,22 +0,0 @@ -import asyncio -import logging - - -from v4_client_py.clients import ValidatorClient, Subaccount -from v4_client_py.clients.constants import Network - -from tests.constants import DYDX_TEST_MNEMONIC - -client = ValidatorClient( - config=Network.testnet().validator_config, -) -subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) -address = subaccount.address - -async def main() -> None: - all_bank_balances = await client.get.bank_balances(address=address) - print(all_bank_balances) - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file diff --git a/v4-client-py/examples/chain_client/GetTx.py b/v4-client-py/examples/chain_client/GetTx.py deleted file mode 100644 index 2a4d9927..00000000 --- a/v4-client-py/examples/chain_client/GetTx.py +++ /dev/null @@ -1,22 +0,0 @@ -import asyncio -import logging - -from v4_client_py.clients import ValidatorClient, Subaccount -from v4_client_py.clients.constants import Network - -from tests.constants import DYDX_TEST_MNEMONIC - -client = ValidatorClient( - config=Network.testnet().validator_config, -) -subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) -address = subaccount.address - -async def main() -> None: - tx_hash = '8247FEF19BB29BD93922803E9919620252DBC0BA4BE7D96E212D8F5EBC122B48' - tx_logs = await client.get.tx(tx_hash=tx_hash) - print(tx_logs) - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file diff --git a/v4-client-py/examples/chain_client/test.py b/v4-client-py/examples/chain_client/test.py deleted file mode 100644 index 39a6e96f..00000000 --- a/v4-client-py/examples/chain_client/test.py +++ /dev/null @@ -1 +0,0 @@ -test='123' \ No newline at end of file diff --git a/v4-client-py/examples/composite_example.py b/v4-client-py/examples/composite_example.py index 04f5b2c9..da34d9ba 100644 --- a/v4-client-py/examples/composite_example.py +++ b/v4-client-py/examples/composite_example.py @@ -1,7 +1,7 @@ -'''Example for trading with human readable numbers +"""Example for trading with human readable numbers Usage: python -m examples.composite_example -''' +""" import asyncio import logging from random import randrange @@ -10,9 +10,9 @@ from v4_client_py.clients.constants import BECH32_PREFIX, Network from v4_client_py.clients.helpers.chain_helpers import ( - OrderType, - OrderSide, - OrderTimeInForce, + OrderType, + OrderSide, + OrderTimeInForce, OrderExecution, ) from examples.utils import loadJson @@ -22,12 +22,12 @@ async def main() -> None: wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) - network = Network.testnet() + network = Network.config_network() client = CompositeClient( network, ) subaccount = Subaccount(wallet, 0) - ordersParams = loadJson('human_readable_orders.json') + ordersParams = loadJson("human_readable_orders.json") for orderParams in ordersParams: type = OrderType[orderParams["type"]] side = OrderSide[orderParams["side"]] @@ -48,7 +48,7 @@ async def main() -> None: try: tx = client.place_order( subaccount, - market='ETH-USD', + market="ETH-USD", type=type, side=side, price=price, @@ -59,39 +59,40 @@ async def main() -> None: good_til_time_in_seconds=time_in_force_seconds, execution=OrderExecution.DEFAULT, post_only=post_only, - reduce_only=False + reduce_only=False, ) - print('**Order Tx**') + print("**Order Tx**") print(tx) except Exception as error: - print('**Order Failed**') + print("**Order Failed**") print(str(error)) await asyncio.sleep(5) # wait for placeOrder to complete - try: tx = client.place_order( subaccount, - market='ETH-USD', + market="ETH-USD", type=OrderType.STOP_MARKET, side=OrderSide.SELL, price=900.0, size=0.01, client_id=randrange(0, 100000000), time_in_force=OrderTimeInForce.GTT, - good_til_block=0, # long term orders use GTBT + good_til_block=0, # long term orders use GTBT good_til_time_in_seconds=1000, execution=OrderExecution.IOC, post_only=False, reduce_only=False, trigger_price=1000, ) - print('**Order Tx**') + print("**Order Tx**") print(tx) except Exception as error: - print('**Order Failed**') + print("**Order Failed**") print(str(error)) -if __name__ == '__main__': + + +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file + asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/faucet_endpoint.py b/v4-client-py/examples/faucet_endpoint.py index bbdb4dcf..e1a6dde4 100644 --- a/v4-client-py/examples/faucet_endpoint.py +++ b/v4-client-py/examples/faucet_endpoint.py @@ -1,14 +1,14 @@ -'''Example for depositing with faucet. +"""Example for depositing with faucet. Usage: python -m examples.faucet_endpoint -''' +""" from v4_client_py.clients import FaucetClient, Subaccount from v4_client_py.clients.constants import Network from tests.constants import DYDX_TEST_MNEMONIC client = FaucetClient( - host=Network.testnet().faucet_endpoint, + host=Network.config_network().faucet_endpoint, ) subaccount = Subaccount.from_mnemonic(DYDX_TEST_MNEMONIC) @@ -19,4 +19,4 @@ faucet_response = client.fill(address, 0, 2000) print(faucet_response.data) faucet_http_code = faucet_response.status_code -print(faucet_http_code) \ No newline at end of file +print(faucet_http_code) diff --git a/v4-client-py/examples/long_term_order_cancel_example.py b/v4-client-py/examples/long_term_order_cancel_example.py index f8950fc4..52703a4a 100644 --- a/v4-client-py/examples/long_term_order_cancel_example.py +++ b/v4-client-py/examples/long_term_order_cancel_example.py @@ -1,7 +1,7 @@ -'''Example for trading with human readable numbers +"""Example for trading with human readable numbers Usage: python -m examples.composite_example -''' +""" import asyncio import logging from random import randrange @@ -11,9 +11,9 @@ from v4_client_py.clients.helpers.chain_helpers import ( ORDER_FLAGS_LONG_TERM, - OrderType, - OrderSide, - OrderTimeInForce, + OrderType, + OrderSide, + OrderTimeInForce, OrderExecution, ) @@ -22,7 +22,7 @@ async def main() -> None: wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) - network = Network.testnet() + network = Network.config_network() client = CompositeClient( network, ) @@ -43,23 +43,23 @@ async def main() -> None: try: tx = client.place_order( subaccount, - market='ETH-USD', + market="ETH-USD", type=OrderType.LIMIT, side=OrderSide.SELL, price=40000, size=0.01, client_id=long_term_order_client_id, time_in_force=OrderTimeInForce.GTT, - good_til_block=0, # long term orders use GTBT + good_til_block=0, # long term orders use GTBT good_til_time_in_seconds=60, execution=OrderExecution.DEFAULT, post_only=False, - reduce_only=False + reduce_only=False, ) - print('** Long Term Order Tx**') + print("** Long Term Order Tx**") print(tx.tx_hash) except Exception as error: - print('**Long Term Order Failed**') + print("**Long Term Order Failed**") print(str(error)) # cancel a long term order. @@ -67,17 +67,18 @@ async def main() -> None: tx = client.cancel_order( subaccount, long_term_order_client_id, - 'ETH-USD', + "ETH-USD", ORDER_FLAGS_LONG_TERM, good_til_time_in_seconds=120, - good_til_block=0, # long term orders use GTBT + good_til_block=0, # long term orders use GTBT ) - print('**Cancel Long Term Order Tx**') + print("**Cancel Long Term Order Tx**") print(tx.tx_hash) except Exception as error: - print('**Cancel Long Term Order Failed**') + print("**Cancel Long Term Order Failed**") print(str(error)) -if __name__ == '__main__': + +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/markets_endpoints.py b/v4-client-py/examples/markets_endpoints.py index 373aefff..3eb0a416 100644 --- a/v4-client-py/examples/markets_endpoints.py +++ b/v4-client-py/examples/markets_endpoints.py @@ -1,93 +1,93 @@ -'''Example for placing, replacing, and canceling orders. +"""Example for placing, replacing, and canceling orders. Usage: python -m examples.markets_endpoints -''' +""" from v4_client_py.clients import IndexerClient from v4_client_py.clients.constants import Network, MARKET_BTC_USD client = IndexerClient( - config=Network.testnet().indexer_config, + config=Network.config_network().indexer_config, ) # Get perp markets try: markets_response = client.markets.get_perpetual_markets() print(markets_response.data) - btc_market = markets_response.data['markets']['BTC-USD'] - btc_market_status = btc_market['status'] + btc_market = markets_response.data["markets"]["BTC-USD"] + btc_market_status = btc_market["status"] except: - print('failed to get markets') + print("failed to get markets") try: btc_market_response = client.markets.get_perpetual_markets(MARKET_BTC_USD) print(btc_market_response.data) - btc_market = btc_market_response.data['markets']['BTC-USD'] - btc_market_status = btc_market['status'] + btc_market = btc_market_response.data["markets"]["BTC-USD"] + btc_market_status = btc_market["status"] except: - print('failed to get BTC market') + print("failed to get BTC market") # Get sparklines try: sparklines_response = client.markets.get_perpetual_markets_sparklines() print(sparklines_response.data) sparklines = sparklines_response.data - btc_sparkline = sparklines['BTC-USD'] + btc_sparkline = sparklines["BTC-USD"] except: - print('failed to get sparklines') + print("failed to get sparklines") # Get perp market trades try: btc_market_trades_response = client.markets.get_perpetual_market_trades(MARKET_BTC_USD) print(btc_market_trades_response.data) - btc_market_trades = btc_market_trades_response.data['trades'] + btc_market_trades = btc_market_trades_response.data["trades"] btc_market_trades_0 = btc_market_trades[0] except: - print('failed to get market trades') + print("failed to get market trades") # Get perp market orderbook try: btc_market_orderbook_response = client.markets.get_perpetual_market_orderbook(MARKET_BTC_USD) print(btc_market_orderbook_response.data) btc_market_orderbook = btc_market_orderbook_response.data - btc_market_orderbook_asks = btc_market_orderbook['asks'] - btc_market_orderbook_bids = btc_market_orderbook['bids'] + btc_market_orderbook_asks = btc_market_orderbook["asks"] + btc_market_orderbook_bids = btc_market_orderbook["bids"] if len(btc_market_orderbook_asks) > 0: btc_market_orderbook_asks_0 = btc_market_orderbook_asks[0] print(btc_market_orderbook_asks_0) - btc_market_orderbook_asks_0_price = btc_market_orderbook_asks_0['price'] - btc_market_orderbook_asks_0_size = btc_market_orderbook_asks_0['size'] + btc_market_orderbook_asks_0_price = btc_market_orderbook_asks_0["price"] + btc_market_orderbook_asks_0_size = btc_market_orderbook_asks_0["size"] except: - print('failed to get market orderbook') + print("failed to get market orderbook") # Get perp market candles try: - btc_market_candles_response = client.markets.get_perpetual_market_candles(MARKET_BTC_USD, '1MIN') + btc_market_candles_response = client.markets.get_perpetual_market_candles(MARKET_BTC_USD, "1MIN") print(btc_market_candles_response.data) - btc_market_candles = btc_market_candles_response.data['candles'] + btc_market_candles = btc_market_candles_response.data["candles"] if len(btc_market_candles) > 0: btc_market_candles_0 = btc_market_candles[0] print(btc_market_candles_0) - btc_market_candles_0_startedAt = btc_market_candles_0['startedAt'] - btc_market_candles_0_low = btc_market_candles_0['low'] - btc_market_candles_0_hight = btc_market_candles_0['high'] - btc_market_candles_0_open = btc_market_candles_0['open'] - btc_market_candles_0_close = btc_market_candles_0['close'] - btc_market_candles_0_baseTokenVolume = btc_market_candles_0['baseTokenVolume'] - btc_market_candles_0_usdVolume = btc_market_candles_0['usdVolume'] - btc_market_candles_0_trades = btc_market_candles_0['trades'] + btc_market_candles_0_startedAt = btc_market_candles_0["startedAt"] + btc_market_candles_0_low = btc_market_candles_0["low"] + btc_market_candles_0_hight = btc_market_candles_0["high"] + btc_market_candles_0_open = btc_market_candles_0["open"] + btc_market_candles_0_close = btc_market_candles_0["close"] + btc_market_candles_0_baseTokenVolume = btc_market_candles_0["baseTokenVolume"] + btc_market_candles_0_usdVolume = btc_market_candles_0["usdVolume"] + btc_market_candles_0_trades = btc_market_candles_0["trades"] except: - print('failed to get market cancles') + print("failed to get market cancles") # Get perp market funding try: btc_market_funding_response = client.markets.get_perpetual_market_funding(MARKET_BTC_USD) print(btc_market_funding_response.data) - btc_market_funding= btc_market_funding_response.data['historicalFunding'] + btc_market_funding = btc_market_funding_response.data["historicalFunding"] if len(btc_market_funding) > 0: btc_market_funding_0 = btc_market_funding[0] print(btc_market_funding_0) except: - print('failed to get market historical funding') + print("failed to get market historical funding") diff --git a/v4-client-py/examples/short_term_order_cancel_example.py b/v4-client-py/examples/short_term_order_cancel_example.py index 01864fa2..a22135bc 100644 --- a/v4-client-py/examples/short_term_order_cancel_example.py +++ b/v4-client-py/examples/short_term_order_cancel_example.py @@ -1,7 +1,7 @@ -'''Example for trading with human readable numbers +"""Example for trading with human readable numbers Usage: python -m examples.composite_example -''' +""" import asyncio import logging from random import randrange @@ -12,14 +12,14 @@ from v4_client_py.clients.helpers.chain_helpers import ( ORDER_FLAGS_SHORT_TERM, Order_TimeInForce, - OrderSide, + OrderSide, ) from tests.constants import DYDX_TEST_MNEMONIC, MAX_CLIENT_ID async def main() -> None: wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) - network = Network.testnet() + network = Network.config_network() client = CompositeClient( network, ) @@ -36,19 +36,19 @@ async def main() -> None: try: tx = client.place_short_term_order( subaccount, - market='ETH-USD', + market="ETH-USD", side=OrderSide.SELL, price=40000, size=0.01, client_id=short_term_client_id, good_til_block=good_til_block, time_in_force=Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED, - reduce_only=False + reduce_only=False, ) - print('**Short Term Order Tx**') + print("**Short Term Order Tx**") print(tx.tx_hash) except Exception as error: - print('**Short Term Order Failed**') + print("**Short Term Order Failed**") print(str(error)) # cancel a short term order. @@ -56,18 +56,18 @@ async def main() -> None: tx = client.cancel_order( subaccount, short_term_client_id, - 'ETH-USD', + "ETH-USD", ORDER_FLAGS_SHORT_TERM, - good_til_time_in_seconds=0, # short term orders use GTB. - good_til_block=good_til_block, # GTB should be the same or greater than order to cancel + good_til_time_in_seconds=0, # short term orders use GTB. + good_til_block=good_til_block, # GTB should be the same or greater than order to cancel ) - print('**Cancel Short Term Order Tx**') + print("**Cancel Short Term Order Tx**") print(tx.tx_hash) except Exception as error: - print('**Cancel Short Term Order Failed**') + print("**Cancel Short Term Order Failed**") print(str(error)) -if __name__ == '__main__': +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) - asyncio.get_event_loop().run_until_complete(main()) \ No newline at end of file + asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/short_term_order_composite_example.py b/v4-client-py/examples/short_term_order_composite_example.py index d80b23fc..e7522dc2 100644 --- a/v4-client-py/examples/short_term_order_composite_example.py +++ b/v4-client-py/examples/short_term_order_composite_example.py @@ -1,7 +1,7 @@ -'''Example for trading with human readable numbers +"""Example for trading with human readable numbers Usage: python -m examples.composite_example -''' +""" import asyncio import logging from random import randrange @@ -10,7 +10,7 @@ from v4_client_py.clients.constants import BECH32_PREFIX, Network from v4_client_py.clients.helpers.chain_helpers import ( - OrderSide, + OrderSide, ) from examples.utils import loadJson, orderExecutionToTimeInForce @@ -19,12 +19,12 @@ async def main() -> None: wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) - network = Network.testnet() + network = Network.config_network() client = CompositeClient( network, ) subaccount = Subaccount(wallet, 0) - ordersParams = loadJson('human_readable_short_term_orders.json') + ordersParams = loadJson("human_readable_short_term_orders.json") for orderParams in ordersParams: side = OrderSide[orderParams["side"]] @@ -34,32 +34,33 @@ async def main() -> None: # Note, you can change this to any number between `next_valid_block_height` to `next_valid_block_height + SHORT_BLOCK_WINDOW` good_til_block = next_valid_block_height + 10 - time_in_force = orderExecutionToTimeInForce(orderParams['timeInForce']) + time_in_force = orderExecutionToTimeInForce(orderParams["timeInForce"]) price = orderParams.get("price", 1350) # uint32 - client_id = randrange(0, 2 ** 32 - 1) + client_id = randrange(0, 2**32 - 1) try: tx = client.place_short_term_order( subaccount, - market='ETH-USD', + market="ETH-USD", side=side, price=price, size=0.01, client_id=client_id, good_til_block=good_til_block, time_in_force=time_in_force, - reduce_only=False + reduce_only=False, ) - print('**Order Tx**') + print("**Order Tx**") print(tx.tx_hash) except Exception as error: - print('**Order Failed**') + print("**Order Failed**") print(str(error)) await asyncio.sleep(5) # wait for placeOrder to complete -if __name__ == '__main__': + +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/transfer_example_deposit.py b/v4-client-py/examples/transfer_example_deposit.py index d58de223..97c73774 100644 --- a/v4-client-py/examples/transfer_example_deposit.py +++ b/v4-client-py/examples/transfer_example_deposit.py @@ -10,9 +10,9 @@ async def main() -> None: - network = Network.testnet() + network = Network.config_network() client = ValidatorClient(network.validator_config) - wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX); + wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) subaccount = Subaccount(wallet, 0) try: tx = client.post.deposit( @@ -20,13 +20,12 @@ async def main() -> None: 0, 5_000_000, ) - print('**Deposit Tx**') + print("**Deposit Tx**") print(tx) except Exception as e: print(e) - -if __name__ == '__main__': +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/transfer_example_subaccount_transfer.py b/v4-client-py/examples/transfer_example_subaccount_transfer.py index 8b23ba2d..01d0c9be 100644 --- a/v4-client-py/examples/transfer_example_subaccount_transfer.py +++ b/v4-client-py/examples/transfer_example_subaccount_transfer.py @@ -10,9 +10,9 @@ async def main() -> None: - network = Network.testnet() + network = Network.config_network() client = ValidatorClient(network.validator_config) - wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX); + wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) subaccount = Subaccount(wallet, 0) try: tx = client.post.transfer( @@ -22,13 +22,12 @@ async def main() -> None: asset_id=0, amount=5_000_000, ) - print('**Transfer Tx**') + print("**Transfer Tx**") print(tx) except Exception as e: print(e) - -if __name__ == '__main__': +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/transfer_example_withdraw.py b/v4-client-py/examples/transfer_example_withdraw.py index d6341259..558cde62 100644 --- a/v4-client-py/examples/transfer_example_withdraw.py +++ b/v4-client-py/examples/transfer_example_withdraw.py @@ -10,9 +10,9 @@ async def main() -> None: - network = Network.testnet() + network = Network.config_network() client = ValidatorClient(network.validator_config) - wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX); + wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) subaccount = Subaccount(wallet, 0) try: tx = client.post.withdraw( @@ -20,13 +20,12 @@ async def main() -> None: 0, 10_000_000, ) - print('**Withdraw Tx**') + print("**Withdraw Tx**") print(tx) except Exception as e: print(e) - -if __name__ == '__main__': +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/utility_endpoints.py b/v4-client-py/examples/utility_endpoints.py index dfca8804..c2fe81d9 100644 --- a/v4-client-py/examples/utility_endpoints.py +++ b/v4-client-py/examples/utility_endpoints.py @@ -1,29 +1,29 @@ -'''Example for getting Indexer server time and height. +"""Example for getting Indexer server time and height. Usage: python -m examples.utility_endpoints -''' +""" from v4_client_py.clients import IndexerClient from v4_client_py.clients.constants import Network client = IndexerClient( - config=Network.testnet().indexer_config, + config=Network.config_network().indexer_config, ) # Get indexer server time try: time_response = client.utility.get_time() print(time_response.data) - time_iso = time_response.data['iso'] - time_epoch = time_response.data['epoch'] + time_iso = time_response.data["iso"] + time_epoch = time_response.data["epoch"] except: - print('failed to get time') + print("failed to get time") # Get indexer height try: height_response = client.utility.get_height() print(height_response.data) - height = height_response.data['height'] - height_time = height_response.data['time'] + height = height_response.data["height"] + height_time = height_response.data["time"] except: - print('failed to get height') + print("failed to get height") diff --git a/v4-client-py/examples/utils.py b/v4-client-py/examples/utils.py index 5ec2ea8b..b1b96710 100644 --- a/v4-client-py/examples/utils.py +++ b/v4-client-py/examples/utils.py @@ -1,4 +1,3 @@ - from enum import Enum import json import os @@ -6,6 +5,7 @@ from v4_client_py.clients.helpers.chain_helpers import Order_TimeInForce, is_order_flag_stateful_order + def loadJson(filename): current_directory = os.path.dirname(os.path.abspath(__file__)) json_file_path = os.path.join(current_directory, filename) @@ -13,12 +13,14 @@ def loadJson(filename): with open(json_file_path, "r") as file: return json.load(file) + class HumanReadableOrderTimeInForce(Enum): DEFAULT = "DEFAULT" FOK = "FOK" IOC = "IOC" POST_ONLY = "POST_ONLY" + def orderExecutionToTimeInForce(orderExecution: HumanReadableOrderTimeInForce) -> Order_TimeInForce: if orderExecution == HumanReadableOrderTimeInForce.DEFAULT.value: return Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED @@ -29,4 +31,4 @@ def orderExecutionToTimeInForce(orderExecution: HumanReadableOrderTimeInForce) - elif orderExecution == HumanReadableOrderTimeInForce.POST_ONLY.value: return Order_TimeInForce.TIME_IN_FORCE_POST_ONLY else: - raise ValueError('Unrecognized order execution') + raise ValueError("Unrecognized order execution") diff --git a/v4-client-py/examples/validator_get_examples.py b/v4-client-py/examples/validator_get_examples.py index 4e17a303..4992ad37 100644 --- a/v4-client-py/examples/validator_get_examples.py +++ b/v4-client-py/examples/validator_get_examples.py @@ -8,91 +8,92 @@ async def main() -> None: - network = Network.testnet() + network = Network.config_network() client = ValidatorClient(network.validator_config) address = DYDX_TEST_ADDRESS try: acc = client.get.account(address=address) - print('account:') + print("account:") print(acc) except Exception as e: - print('failed to get account') + print("failed to get account") print(e) try: bank_balances = client.get.bank_balances(address) - print('bank balances:') + print("bank balances:") print(bank_balances) except Exception as e: - print('failed to get bank balances') + print("failed to get bank balances") print(e) try: - bank_balance = client.get.bank_balance(address, 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5') - print('bank balance:') + bank_balance = client.get.bank_balance( + address, "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5" + ) + print("bank balance:") print(bank_balance) except Exception as e: - print('failed to get bank balances') + print("failed to get bank balances") print(e) - try: all_subaccounts = client.get.subaccounts() - print('subaccounts:') + print("subaccounts:") print(all_subaccounts) except Exception as e: - print('failed to get all subaccounts') + print("failed to get all subaccounts") print(e) try: subaccount = client.get.subaccount(address, 0) - print('subaccount:') + print("subaccount:") print(subaccount) except Exception as e: - print('failed to get subaccount') + print("failed to get subaccount") print(e) try: clob_pairs = client.get.clob_pairs() - print('clob pairs:') + print("clob pairs:") print(clob_pairs) except Exception as e: - print('failed to get all clob pairs') + print("failed to get all clob pairs") print(e) try: clob_pair = client.get.clob_pair(1) - print('clob pair:') + print("clob pair:") print(clob_pair) except Exception as e: - print('failed to get clob pair') + print("failed to get clob pair") print(e) try: prices = client.get.prices() - print('prices:') + print("prices:") print(prices) except Exception as e: - print('failed to get all prices') + print("failed to get all prices") print(e) try: price = client.get.price(1) - print('price:') + print("price:") print(price) except Exception as e: - print('failed to get price') + print("failed to get price") print(e) try: config = client.get.equity_tier_limit_config() - print('equity_tier_limit_configuration:') + print("equity_tier_limit_configuration:") print(config) except Exception as e: - print('failed to get equity_tier_limit_configuration') + print("failed to get equity_tier_limit_configuration") print(e) -if __name__ == '__main__': +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/validator_post_examples.py b/v4-client-py/examples/validator_post_examples.py index cb3c7815..9303fb8a 100644 --- a/v4-client-py/examples/validator_post_examples.py +++ b/v4-client-py/examples/validator_post_examples.py @@ -28,6 +28,7 @@ "client_metadata": 0, } + def dummy_order(height): placeOrder = default_order.copy() placeOrder["client_id"] = random.randint(0, 1000000000) @@ -40,12 +41,13 @@ def dummy_order(height): placeOrder["side"] = Order.SIDE_SELL return placeOrder + async def main() -> None: - network = Network.testnet() + network = Network.config_network() client = ValidatorClient(network.validator_config) - wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX); + wallet = LocalWallet.from_mnemonic(DYDX_TEST_MNEMONIC, BECH32_PREFIX) subaccount = Subaccount(wallet, 0) - ordersParams = loadJson('raw_orders.json') + ordersParams = loadJson("raw_orders.json") for orderParams in ordersParams: last_block = client.get.latest_block() height = last_block.block.header.height @@ -70,14 +72,15 @@ async def main() -> None: place_order["good_til_block_time"] = 0 tx = client.post.place_order_object(subaccount, place_order) - print('**Order Tx**') + print("**Order Tx**") print(tx) except Exception as error: - print('**Order Failed**') + print("**Order Failed**") print(str(error)) await asyncio.sleep(5) # wait for placeOrder to complete -if __name__ == '__main__': + +if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/examples/wallet_address.py b/v4-client-py/examples/wallet_address.py index 383b6c44..746ca608 100644 --- a/v4-client-py/examples/wallet_address.py +++ b/v4-client-py/examples/wallet_address.py @@ -6,10 +6,10 @@ # We recommend using comspy to derive address from mnemonic wallet = LocalWallet.from_mnemonic(mnemonic=DYDX_TEST_MNEMONIC, prefix=BECH32_PREFIX) private_key = wallet.signer().private_key_hex -assert(private_key==DYDX_TEST_PRIVATE_KEY) +assert private_key == DYDX_TEST_PRIVATE_KEY public_key = wallet.public_key().public_key_hex address = wallet.address() -print(f'public key:{public_key}, address:{address}') +print(f"public key:{public_key}, address:{address}") -assert(address==DYDX_TEST_ADDRESS) \ No newline at end of file +assert address == DYDX_TEST_ADDRESS diff --git a/v4-client-py/examples/websocket_example.py b/v4-client-py/examples/websocket_example.py index 5b764762..bf54367d 100644 --- a/v4-client-py/examples/websocket_example.py +++ b/v4-client-py/examples/websocket_example.py @@ -1,7 +1,7 @@ -'''Example for connecting to private WebSockets with an existing account. +"""Example for connecting to private WebSockets with an existing account. Usage: python -m examples.websocket_example -''' +""" import asyncio import json @@ -11,29 +11,31 @@ from tests.constants import DYDX_TEST_ADDRESS + def on_open(ws): - print('WebSocket connection opened') + print("WebSocket connection opened") ws.send_ping_if_inactive_for(30) + def on_message(ws, message): - print(f'Received message: {message}') + print(f"Received message: {message}") payload = json.loads(message) - if (payload['type'] == 'connected'): + if payload["type"] == "connected": my_ws.subscribe_to_markets() - my_ws.subscribe_to_orderbook('ETH-USD') - my_ws.subscribe_to_trades('ETH-USD') - my_ws.subscribe_to_candles('ETH-USD') + my_ws.subscribe_to_orderbook("ETH-USD") + my_ws.subscribe_to_trades("ETH-USD") + my_ws.subscribe_to_candles("ETH-USD") my_ws.subscribe_to_subaccount(DYDX_TEST_ADDRESS, 0) ws.send_ping_if_inactive_for(30) ws.subscribe_to_markets() + def on_close(ws): - print('WebSocket connection closed') + print("WebSocket connection closed") + + +my_ws = SocketClient(config=Network.config_network().indexer_config, on_message=on_message, on_open=on_open, on_close=on_close) -my_ws = SocketClient(config=Network.testnet().indexer_config, - on_message=on_message, - on_open=on_open, - on_close=on_close) async def main(): my_ws.connect() @@ -41,4 +43,6 @@ async def main(): # Do some stuff... # my_ws.close() + + asyncio.get_event_loop().run_until_complete(main()) diff --git a/v4-client-py/v4_client_py/chain/aerial/config.py b/v4-client-py/v4_client_py/chain/aerial/config.py index 97c6b2b4..77c5ce8c 100644 --- a/v4-client-py/v4_client_py/chain/aerial/config.py +++ b/v4-client-py/v4_client_py/chain/aerial/config.py @@ -1,16 +1,17 @@ - """Network configurations.""" import warnings from dataclasses import dataclass from typing import Optional, Union + class NetworkConfigError(RuntimeError): """Network config error. :param RuntimeError: Runtime error """ + URL_PREFIXES = ( "grpc+https", "grpc+http", @@ -45,16 +46,12 @@ def validate(self): raise NetworkConfigError("URL must be set") if not any( map( - lambda x: self.url.startswith( # noqa: # pylint: disable=unnecessary-lambda - x - ), + lambda x: self.url.startswith(x), # noqa: # pylint: disable=unnecessary-lambda URL_PREFIXES, ) ): prefix_list = ", ".join(map(lambda x: f'"{x}"', URL_PREFIXES)) - raise NetworkConfigError( - f"URL must start with one of the following prefixes: {prefix_list}" - ) + raise NetworkConfigError(f"URL must start with one of the following prefixes: {prefix_list}") @classmethod def fetchai_dorado_testnet(cls) -> "NetworkConfig": @@ -71,21 +68,6 @@ def fetchai_dorado_testnet(cls) -> "NetworkConfig": faucet_url="https://faucet-dorado.fetch.ai", ) - @classmethod - def fetch_dydx_testnet(cls) -> "NetworkConfig": - """Dydx testnet. - - :return: Network configuration - """ - return NetworkConfig( - chain_id="dydx-testnet-4", - url="grpc+https://dydx-testnet-archive.allthatnode.com:9090", - fee_minimum_gas_price=4630550000000000, - fee_denomination="adv4tnt", - staking_denomination="dv4tnt", - faucet_url="http://faucet.v4testnet.dydx.exchange", - ) - @classmethod def fetchai_alpha_testnet(cls): """Get the fetchai alpha testnet. @@ -110,33 +92,6 @@ def fetch_dydx_stable_testnet(cls): """ return cls.fetch_dydx_testnet() - @classmethod - def fetchai_mainnet(cls) -> "NetworkConfig": - """Get the fetchai mainnet configuration. - - :return: fetch mainnet configuration - """ - return NetworkConfig( - chain_id="fetchhub-4", - url="grpc+https://grpc-fetchhub.fetch.ai", - fee_minimum_gas_price=0, - fee_denomination="afet", - staking_denomination="afet", - faucet_url=None, - ) - - @classmethod - def fetch_mainnet(cls) -> "NetworkConfig": - """Get the fetch mainnet. - - :return: fetch mainnet configurations - """ - warnings.warn( - "fetch_mainnet is deprecated, use fetchai_mainnet instead", - DeprecationWarning, - ) - return cls.fetchai_mainnet() - @classmethod def latest_stable_testnet(cls) -> "NetworkConfig": """Get the latest stable testnet. @@ -148,3 +103,18 @@ def latest_stable_testnet(cls) -> "NetworkConfig": DeprecationWarning, ) return cls.fetch_dydx_stable_testnet() + + @classmethod + def fetchai_network_config(cls, chain_id: str, url_prefix: str, url: str) -> "NetworkConfig": + """Get the fetchai mainnet configuration. + + :return: fetch mainnet configuration + """ + return cls( + chain_id=chain_id, + url=f"{url_prefix}+{url}", + fee_minimum_gas_price=0, + fee_denomination="afet", + staking_denomination="afet", + faucet_url=None, + ) diff --git a/v4-client-py/v4_client_py/clients/constants.py b/v4-client-py/v4_client_py/clients/constants.py index 86920ca4..4e0d202e 100644 --- a/v4-client-py/v4_client_py/clients/constants.py +++ b/v4-client-py/v4_client_py/clients/constants.py @@ -1,75 +1,63 @@ from enum import Enum -from ..chain.aerial.config import NetworkConfig - -# ------------ API URLs ------------ -INDEXER_API_HOST_MAINNET = None -INDEXER_API_HOST_TESTNET = 'https://dydx-testnet.imperator.co' - -INDEXER_WS_HOST_MAINNET = None -INDEXER_WS_HOST_TESTNET = 'wss://indexer.v4testnet.dydx.exchange/v4/ws' - -FAUCET_API_HOST_TESTNET = 'https://faucet.v4testnet.dydx.exchange' - -VALIDATOR_API_HOST_MAINNET = None -VALIDATOR_API_HOST_TESTNET = 'https://dydx-testnet-archive.allthatnode.com' - -VALIDATOR_GRPC_MAINNET = None -VALIDATOR_GRPC_TESTNET = 'dydx-testnet-archive.allthatnode.com:9090' - -# ------------ Ethereum Network IDs ------------ -NETWORK_ID_MAINNET = None -NETWORK_ID_TESTNET = 'dydx-testnet-4' +# define constants +VALIDATOR_GRPC_ENDPOINT = '{get from deployer}' +AERIAL_CONFIG_URL = '{get from deployer}' +AERIAL_GRPC_OR_REST_PREFIX = '{get from deployer}' +INDEXER_REST_ENDPOINT = '{get from deployer}' +INDEXER_WS_ENDPOINT = '{get from deployer}' +CHAIN_ID = '{get from deployer}' +ENV = '{get from deployer}' # ------------ Market Statistic Day Types ------------ -MARKET_STATISTIC_DAY_ONE = '1' -MARKET_STATISTIC_DAY_SEVEN = '7' -MARKET_STATISTIC_DAY_THIRTY = '30' +MARKET_STATISTIC_DAY_ONE = "1" +MARKET_STATISTIC_DAY_SEVEN = "7" +MARKET_STATISTIC_DAY_THIRTY = "30" # ------------ Order Types ------------ -ORDER_TYPE_LIMIT = 'LIMIT' -ORDER_TYPE_MARKET = 'MARKET' -ORDER_TYPE_STOP = 'STOP_LIMIT' -ORDER_TYPE_TRAILING_STOP = 'TRAILING_STOP' -ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT' +ORDER_TYPE_LIMIT = "LIMIT" +ORDER_TYPE_MARKET = "MARKET" +ORDER_TYPE_STOP = "STOP_LIMIT" +ORDER_TYPE_TRAILING_STOP = "TRAILING_STOP" +ORDER_TYPE_TAKE_PROFIT = "TAKE_PROFIT" # ------------ Order Side ------------ -ORDER_SIDE_BUY = 'BUY' -ORDER_SIDE_SELL = 'SELL' +ORDER_SIDE_BUY = "BUY" +ORDER_SIDE_SELL = "SELL" # ------------ Time in Force Types ------------ -TIME_IN_FORCE_GTT = 'GTT' -TIME_IN_FORCE_FOK = 'FOK' -TIME_IN_FORCE_IOC = 'IOC' +TIME_IN_FORCE_GTT = "GTT" +TIME_IN_FORCE_FOK = "FOK" +TIME_IN_FORCE_IOC = "IOC" # ------------ Position Status Types ------------ -POSITION_STATUS_OPEN = 'OPEN' -POSITION_STATUS_CLOSED = 'CLOSED' -POSITION_STATUS_LIQUIDATED = 'LIQUIDATED' +POSITION_STATUS_OPEN = "OPEN" +POSITION_STATUS_CLOSED = "CLOSED" +POSITION_STATUS_LIQUIDATED = "LIQUIDATED" # ------------ Order Status Types ------------ -ORDER_STATUS_PENDING = 'PENDING' -ORDER_STATUS_OPEN = 'OPEN' -ORDER_STATUS_FILLED = 'FILLED' -ORDER_STATUS_CANCELED = 'CANCELED' -ORDER_STATUS_UNTRIGGERED = 'UNTRIGGERED' +ORDER_STATUS_PENDING = "PENDING" +ORDER_STATUS_OPEN = "OPEN" +ORDER_STATUS_FILLED = "FILLED" +ORDER_STATUS_CANCELED = "CANCELED" +ORDER_STATUS_UNTRIGGERED = "UNTRIGGERED" # ------------ Transfer Status Types ------------ -TRANSFER_STATUS_PENDING = 'PENDING' -TRANSFER_STATUS_CONFIRMED = 'CONFIRMED' -TRANSFER_STATUS_QUEUED = 'QUEUED' -TRANSFER_STATUS_CANCELED = 'CANCELED' -TRANSFER_STATUS_UNCONFIRMED = 'UNCONFIRMED' +TRANSFER_STATUS_PENDING = "PENDING" +TRANSFER_STATUS_CONFIRMED = "CONFIRMED" +TRANSFER_STATUS_QUEUED = "QUEUED" +TRANSFER_STATUS_CANCELED = "CANCELED" +TRANSFER_STATUS_UNCONFIRMED = "UNCONFIRMED" # ------------ Markets ------------ -MARKET_BTC_USD = 'BTC-USD' -MARKET_ETH_USD = 'ETH-USD' +MARKET_BTC_USD = "BTC-USD" +MARKET_ETH_USD = "ETH-USD" # ------------ Assets ------------ -ASSET_USDC = 'USDC' -ASSET_BTC = 'BTC' -ASSET_ETH = 'ETH' +ASSET_USDC = "USDC" +ASSET_BTC = "BTC" +ASSET_ETH = "ETH" COLLATERAL_ASSET = ASSET_USDC # ------------ Synthetic Assets by Market ------------ @@ -83,7 +71,8 @@ MAX_MEMO_CHARACTERS = 256 -BECH32_PREFIX = 'dydx' +BECH32_PREFIX = "dydx" + class BroadcastMode(Enum): BroadcastTxSync = 0 @@ -96,21 +85,19 @@ def __init__( rest_endpoint: str, websocket_endpoint: str, ): - if rest_endpoint.endswith('/'): + if rest_endpoint.endswith("/"): rest_endpoint = rest_endpoint[:-1] self.rest_endpoint = rest_endpoint self.websocket_endpoint = websocket_endpoint + class ValidatorConfig: - def __init__( - self, - grpc_endpoint: str, - chain_id: str, - ssl_enabled: bool, - ): + def __init__(self, grpc_endpoint: str, chain_id: str, ssl_enabled: bool, url_prefix: str, aerial_url: str): self.grpc_endpoint = grpc_endpoint self.chain_id = chain_id self.ssl_enabled = ssl_enabled + self.url_prefix = url_prefix + self.url = aerial_url class Network: @@ -124,45 +111,25 @@ def __init__( self.env = env self.validator_config = validator_config self.indexer_config = indexer_config - if faucet_endpoint is not None and faucet_endpoint.endswith('/'): + if faucet_endpoint is not None and faucet_endpoint.endswith("/"): faucet_endpoint = faucet_endpoint[:-1] self.faucet_endpoint = faucet_endpoint @classmethod - def testnet(cls): - validator_config=ValidatorConfig( - grpc_endpoint=VALIDATOR_GRPC_TESTNET, - chain_id=NETWORK_ID_TESTNET, - ssl_enabled=True - ) - indexer_config=IndexerConfig( - rest_endpoint=INDEXER_API_HOST_TESTNET, - websocket_endpoint=INDEXER_WS_HOST_TESTNET, - ) - return cls( - env='testnet', - validator_config=validator_config, - indexer_config=indexer_config, - faucet_endpoint=FAUCET_API_HOST_TESTNET, - ) - - @classmethod - def mainnet(cls): - validator_config=ValidatorConfig( - grpc_endpoint=VALIDATOR_GRPC_MAINNET, - chain_id=NETWORK_ID_MAINNET, - ssl_enabled=True - ) - indexer_config=IndexerConfig( - rest_endpoint=INDEXER_API_HOST_MAINNET, - websocket_endpoint=INDEXER_WS_HOST_MAINNET, + def config_network( + cls + ) -> "Network": + validator_config = ValidatorConfig( + grpc_endpoint=VALIDATOR_GRPC_ENDPOINT, + chain_id=CHAIN_ID, + ssl_enabled=True, + url_prefix=AERIAL_GRPC_OR_REST_PREFIX, + aerial_url=AERIAL_CONFIG_URL, ) + indexer_config = IndexerConfig(rest_endpoint=INDEXER_REST_ENDPOINT, websocket_endpoint=INDEXER_WS_ENDPOINT) return cls( - env='mainnet', + env=ENV, validator_config=validator_config, indexer_config=indexer_config, faucet_endpoint=None, ) - - def string(self): - return self.env diff --git a/v4-client-py/v4_client_py/clients/dydx_composite_client.py b/v4-client-py/v4_client_py/clients/dydx_composite_client.py index 11d71f87..627e50f1 100644 --- a/v4-client-py/v4_client_py/clients/dydx_composite_client.py +++ b/v4-client-py/v4_client_py/clients/dydx_composite_client.py @@ -8,14 +8,14 @@ QUOTE_QUANTUMS_ATOMIC_RESOLUTION, Order, Order_TimeInForce, - OrderType, - OrderSide, - OrderTimeInForce, + OrderType, + OrderSide, + OrderTimeInForce, OrderExecution, calculate_side, - calculate_quantums, - calculate_subticks, - calculate_time_in_force, + calculate_quantums, + calculate_subticks, + calculate_time_in_force, calculate_order_flags, ORDER_FLAGS_SHORT_TERM, SHORT_BLOCK_WINDOW, @@ -34,9 +34,9 @@ class CompositeClient: def __init__( self, network: Network, - api_timeout = None, - send_options = None, - credentials = grpc.ssl_channel_credentials(), + api_timeout=None, + send_options=None, + credentials=grpc.ssl_channel_credentials(), ): self.indexer_client = IndexerClient(network.indexer_config, api_timeout, send_options) self.validator_client = ValidatorClient(network.validator_config, credentials) @@ -61,8 +61,7 @@ def generate_good_til_fields( good_til_block: int, good_til_time_in_seconds: int, ) -> Tuple[int, int]: - is_stateful_order = is_order_flag_stateful_order(order_flags) - if is_stateful_order: + if is_stateful_order := is_order_flag_stateful_order(order_flags): return 0, self.calculate_good_til_block_time(good_til_time_in_seconds) else: return good_til_block, 0 @@ -101,7 +100,7 @@ def place_order( reduce_only: bool, trigger_price: float = None, ) -> SubmittedTx: - ''' + """ Place order :param subaccount: required @@ -141,7 +140,7 @@ def place_order( :type reduce_only: bool :returns: Tx information - ''' + """ msg = self.place_order_message( subaccount=subaccount, market=market, @@ -172,7 +171,7 @@ def place_short_term_order( time_in_force: Order_TimeInForce, reduce_only: bool, ) -> SubmittedTx: - ''' + """ Place Short-Term order :param subaccount: required @@ -203,7 +202,7 @@ def place_short_term_order( :type reduce_only: bool :returns: Tx information - ''' + """ msg = self.place_short_term_order_message( subaccount=subaccount, market=market, @@ -217,27 +216,35 @@ def place_short_term_order( reduce_only=reduce_only, ) return self.validator_client.post.send_message(subaccount=subaccount, msg=msg, zeroFee=True) - + def calculate_client_metadata(self, order_type: OrderType) -> int: - ''' + """ Calculate Client Metadata :param order_type: required :type order_type: OrderType :returns: Client Metadata - ''' - return 1 if (order_type == OrderType.MARKET or order_type == OrderType.STOP_MARKET or order_type == OrderType.TAKE_PROFIT_MARKET) else 0 + """ + return ( + 1 + if ( + order_type == OrderType.MARKET + or order_type == OrderType.STOP_MARKET + or order_type == OrderType.TAKE_PROFIT_MARKET + ) + else 0 + ) def calculate_condition_type(self, order_type: OrderType) -> Order.ConditionType: - ''' + """ Calculate Condition Type :param order_type: required :type order_type: OrderType :returns: Condition Type - ''' + """ if order_type == OrderType.LIMIT: return Order.CONDITION_TYPE_UNSPECIFIED elif order_type == OrderType.MARKET: @@ -247,17 +254,17 @@ def calculate_condition_type(self, order_type: OrderType) -> Order.ConditionType elif order_type == OrderType.TAKE_PROFIT_LIMIT or order_type == OrderType.TAKE_PROFIT_MARKET: return Order.CONDITION_TYPE_TAKE_PROFIT else: - raise ValueError('order_type is invalid') + raise ValueError("order_type is invalid") def calculate_conditional_order_trigger_subticks( - self, - order_type: OrderType, - atomic_resolution: int, - quantum_conversion_exponent: int, - subticks_per_tick: int, - trigger_price: float, - ) -> int: - ''' + self, + order_type: OrderType, + atomic_resolution: int, + quantum_conversion_exponent: int, + subticks_per_tick: int, + trigger_price: float, + ) -> int: + """ Calculate Conditional Order Trigger Subticks :param order_type: required @@ -276,15 +283,20 @@ def calculate_conditional_order_trigger_subticks( :type trigger_price: float :returns: Conditional Order Trigger Subticks - ''' + """ if order_type == OrderType.LIMIT or order_type == OrderType.MARKET: return 0 - elif order_type == OrderType.STOP_LIMIT or order_type == OrderType.STOP_MARKET or order_type == OrderType.TAKE_PROFIT_LIMIT or order_type == OrderType.TAKE_PROFIT_MARKET: + elif ( + order_type == OrderType.STOP_LIMIT + or order_type == OrderType.STOP_MARKET + or order_type == OrderType.TAKE_PROFIT_LIMIT + or order_type == OrderType.TAKE_PROFIT_MARKET + ): if trigger_price is None: - raise ValueError('trigger_price is required for conditional orders') + raise ValueError("trigger_price is required for conditional orders") return calculate_subticks(trigger_price, atomic_resolution, quantum_conversion_exponent, subticks_per_tick) else: - raise ValueError('order_type is invalid') + raise ValueError("order_type is invalid") def place_order_message( self, @@ -304,12 +316,12 @@ def place_order_message( trigger_price: float = None, ) -> MsgPlaceOrder: markets_response = self.indexer_client.markets.get_perpetual_markets(market) - market = markets_response.data['markets'][market] - clob_pair_id = market['clobPairId'] - atomic_resolution = market['atomicResolution'] - step_base_quantums = market['stepBaseQuantums'] - quantum_conversion_exponent = market['quantumConversionExponent'] - subticks_per_tick = market['subticksPerTick'] + market = markets_response.data["markets"][market] + clob_pair_id = market["clobPairId"] + atomic_resolution = market["atomicResolution"] + step_base_quantums = market["stepBaseQuantums"] + quantum_conversion_exponent = market["quantumConversionExponent"] + subticks_per_tick = market["subticksPerTick"] order_side = calculate_side(side) quantums = calculate_quantums(size, atomic_resolution, step_base_quantums) subticks = calculate_subticks(price, atomic_resolution, quantum_conversion_exponent, subticks_per_tick) @@ -323,12 +335,8 @@ def place_order_message( client_metadata = self.calculate_client_metadata(type) condition_type = self.calculate_condition_type(type) conditional_order_trigger_subticks = self.calculate_conditional_order_trigger_subticks( - type, - atomic_resolution, - quantum_conversion_exponent, - subticks_per_tick, - trigger_price - ) + type, atomic_resolution, quantum_conversion_exponent, subticks_per_tick, trigger_price + ) return self.validator_client.post.composer.compose_msg_place_order( address=subaccount.address, subaccount_number=subaccount.subaccount_number, @@ -365,12 +373,12 @@ def place_short_term_order_message( # Construct the MsgPlaceOrder. markets_response = self.indexer_client.markets.get_perpetual_markets(market) - market = markets_response.data['markets'][market] - clob_pair_id = market['clobPairId'] - atomic_resolution = market['atomicResolution'] - step_base_quantums = market['stepBaseQuantums'] - quantum_conversion_exponent = market['quantumConversionExponent'] - subticks_per_tick = market['subticksPerTick'] + market = markets_response.data["markets"][market] + clob_pair_id = market["clobPairId"] + atomic_resolution = market["atomicResolution"] + step_base_quantums = market["stepBaseQuantums"] + quantum_conversion_exponent = market["quantumConversionExponent"] + subticks_per_tick = market["subticksPerTick"] order_side = calculate_side(side) quantums = calculate_quantums(size, atomic_resolution, step_base_quantums) subticks = calculate_subticks(price, atomic_resolution, quantum_conversion_exponent, subticks_per_tick) @@ -395,15 +403,15 @@ def place_short_term_order_message( ) def cancel_order( - self, + self, subaccount: Subaccount, client_id: int, market: str, order_flags: int, good_til_time_in_seconds: int, good_til_block: int, - ) -> SubmittedTx: - ''' + ) -> SubmittedTx: + """ Cancel order :param subaccount: required @@ -425,7 +433,7 @@ def cancel_order( :type good_til_block_time: int :returns: Tx information - ''' + """ msg = self.cancel_order_message( subaccount, market, @@ -437,15 +445,14 @@ def cancel_order( return self.validator_client.post.send_message(subaccount=subaccount, msg=msg, zeroFee=True) - def cancel_short_term_order( self, subaccount: Subaccount, client_id: int, market: str, good_til_block: int, - ) -> SubmittedTx: - ''' + ) -> SubmittedTx: + """ Cancel order :param subaccount: required @@ -461,7 +468,7 @@ def cancel_short_term_order( :type good_til_block: int :returns: Tx information - ''' + """ msg = self.cancel_order_message( subaccount, market, @@ -473,7 +480,6 @@ def cancel_short_term_order( return self.validator_client.post.send_message(subaccount=subaccount, msg=msg, zeroFee=True) - def cancel_order_message( self, subaccount: Subaccount, @@ -489,8 +495,8 @@ def cancel_order_message( # Construct the MsgPlaceOrder. markets_response = self.indexer_client.markets.get_perpetual_markets(market) - market = markets_response.data['markets'][market] - clob_pair_id = market['clobPairId'] + market = markets_response.data["markets"][market] + clob_pair_id = market["clobPairId"] good_til_block, good_til_block_time = self.generate_good_til_fields( order_flags, @@ -508,15 +514,14 @@ def cancel_order_message( good_til_block_time=good_til_block_time, ) - def transfer_to_subaccount( - self, + self, subaccount: Subaccount, recipient_address: str, recipient_subaccount_number: int, amount: float, - ) -> SubmittedTx: - ''' + ) -> SubmittedTx: + """ Cancel order :param subaccount: required @@ -532,7 +537,7 @@ def transfer_to_subaccount( :type amount: float :returns: Tx information - ''' + """ return self.validator_client.post.transfer( subaccount=subaccount, recipient_address=recipient_address, @@ -540,13 +545,13 @@ def transfer_to_subaccount( asset_id=0, amount=amount * 10**6, ) - + def deposit_to_subaccount( - self, + self, subaccount: Subaccount, amount: float, - ) -> SubmittedTx: - ''' + ) -> SubmittedTx: + """ Cancel order :param subaccount: required @@ -556,19 +561,19 @@ def deposit_to_subaccount( :type amount: float :returns: Tx information - ''' + """ return self.validator_client.post.deposit( subaccount=subaccount, asset_id=0, - quantums=amount * 10 ** (- QUOTE_QUANTUMS_ATOMIC_RESOLUTION), + quantums=amount * 10 ** (-QUOTE_QUANTUMS_ATOMIC_RESOLUTION), ) - + def withdraw_from_subaccount( - self, + self, subaccount: Subaccount, amount: float, - ) -> SubmittedTx: - ''' + ) -> SubmittedTx: + """ Cancel order :param subaccount: required @@ -578,9 +583,9 @@ def withdraw_from_subaccount( :type amount: float :returns: Tx information - ''' + """ return self.validator_client.post.withdraw( subaccount=subaccount, asset_id=0, - quantums=amount * 10 ** (- QUOTE_QUANTUMS_ATOMIC_RESOLUTION), + quantums=amount * 10 ** (-QUOTE_QUANTUMS_ATOMIC_RESOLUTION), ) diff --git a/v4-client-py/v4_client_py/clients/dydx_socket_client.py b/v4-client-py/v4_client_py/clients/dydx_socket_client.py index 2a462d7b..85833fde 100644 --- a/v4-client-py/v4_client_py/clients/dydx_socket_client.py +++ b/v4-client-py/v4_client_py/clients/dydx_socket_client.py @@ -19,8 +19,6 @@ def __init__( self.on_open = on_open self.on_close = on_close self.last_activity_time = None - self.ping_thread = None - self.ping_sent_time = None def connect(self): self.ws = websocket.WebSocketApp(self.url, @@ -36,17 +34,9 @@ def _on_open(self, ws): else: print('WebSocket connection opened') self.last_activity_time = time.time() - self.ping_thread = threading.Thread(target=self._ping_thread_func) - self.ping_thread.start() def _on_message(self, ws, message): - if message == 'ping': - self.send('pong') - elif message == 'pong' and self.ping_sent_time is not None: - elapsed_time = time.time() - self.ping_sent_time - print(f'Received PONG after {elapsed_time:.2f} seconds') - self.ping_sent_time = None - elif self.on_message: + if self.on_message: self.on_message(ws, message) else: print(f'Received message: {message}') @@ -58,7 +48,6 @@ def _on_close(self, ws): else: print('WebSocket connection closed') self.last_activity_time = None - self.ping_thread = None def send(self, message): if self.ws: @@ -67,24 +56,6 @@ def send(self, message): else: print('Error: WebSocket is not connected') - def send_ping(self): - self.send('ping') - self.ping_sent_time = time.time() - - def _ping_thread_func(self): - while self.ws: - if self.last_activity_time and time.time() - self.last_activity_time > 30: - self.send_ping() - self.last_activity_time = time.time() - elif self.ping_sent_time and time.time() - self.ping_sent_time > 5: - print('Did not receive PONG in time, closing WebSocket...') - self.close() - break - time.sleep(1) - - def send_ping_if_inactive_for(self, duration): - self.last_activity_time = time.time() - duration - def close(self): if self.ws: self.ws.close() diff --git a/v4-client-py/v4_client_py/clients/modules/post.py b/v4-client-py/v4_client_py/clients/modules/post.py index 7fc1bc7f..ec8395b4 100644 --- a/v4-client-py/v4_client_py/clients/modules/post.py +++ b/v4-client-py/v4_client_py/clients/modules/post.py @@ -14,6 +14,7 @@ from ...chain.aerial.client import LedgerClient, NetworkConfig from ...chain.aerial.client.utils import prepare_and_broadcast_basic_transaction + class Post: def __init__( self, @@ -29,8 +30,7 @@ def send_message( zeroFee: bool = False, broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: - - ''' + """ Send a message :param subaccount: required @@ -40,25 +40,28 @@ def send_message( :type msg: Message :returns: Tx information - ''' + """ wallet = subaccount.wallet - network = NetworkConfig.fetch_dydx_testnet() + network = NetworkConfig.fetchai_network_config( + chain_id=self.config.chain_id, url_prefix=self.config.url_prefix, url=self.config.url + ) ledger = LedgerClient(network) + tx = Transaction() tx.add_message(msg) gas_limit = 0 if zeroFee else None return prepare_and_broadcast_basic_transaction( - client=ledger, - tx=tx, - sender=wallet, + client=ledger, + tx=tx, + sender=wallet, gas_limit=gas_limit, memo=None, broadcast_mode=broadcast_mode if (broadcast_mode != None) else self.default_broadcast_mode(msg), fee=0 if zeroFee else None, - ) - + ) + def place_order( self, subaccount: Subaccount, @@ -73,11 +76,11 @@ def place_order( good_til_block: int, good_til_block_time: int, client_metadata: int, - condition_type: Order.ConditionType=Order.ConditionType.CONDITION_TYPE_UNSPECIFIED, - conditional_order_trigger_subticks: int=0, - broadcast_mode: BroadcastMode=None, + condition_type: Order.ConditionType = Order.ConditionType.CONDITION_TYPE_UNSPECIFIED, + conditional_order_trigger_subticks: int = 0, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: - ''' + """ Place order :param subaccount: required @@ -114,40 +117,34 @@ def place_order( :type reduce_only: bool :returns: Tx information - ''' + """ # prepare tx msg subaccount_number = subaccount.subaccount_number msg = self.composer.compose_msg_place_order( address=subaccount.address, - subaccount_number=subaccount_number, - client_id=client_id, - clob_pair_id=clob_pair_id, - order_flags=order_flags, - good_til_block=good_til_block, - good_til_block_time=good_til_block_time, - side=side, - quantums=quantums, - subticks=subticks, - time_in_force=time_in_force, + subaccount_number=subaccount_number, + client_id=client_id, + clob_pair_id=clob_pair_id, + order_flags=order_flags, + good_til_block=good_til_block, + good_til_block_time=good_til_block_time, + side=side, + quantums=quantums, + subticks=subticks, + time_in_force=time_in_force, reduce_only=reduce_only, client_metadata=client_metadata, condition_type=condition_type, conditional_order_trigger_subticks=conditional_order_trigger_subticks, - ) - return self.send_message( - subaccount=subaccount, - msg=msg, - zeroFee=True, - broadcast_mode=broadcast_mode ) - + return self.send_message(subaccount=subaccount, msg=msg, zeroFee=True, broadcast_mode=broadcast_mode) def place_order_object( self, subaccount: Subaccount, place_order: any, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: return self.place_order( subaccount, @@ -173,9 +170,9 @@ def cancel_order( order_flags: int, good_til_block: int, good_til_block_time: int, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: - ''' + """ Cancel order :param subaccount: required @@ -200,23 +197,23 @@ def cancel_order( :type broadcast_mode: BroadcastMode :returns: Tx information - ''' + """ msg = self.composer.compose_msg_cancel_order( - subaccount.address, + subaccount.address, subaccount.subaccount_number, client_id, clob_pair_id, order_flags, good_til_block, good_til_block_time, - ) + ) return self.send_message(subaccount, msg, zeroFee=True, broadcast_mode=broadcast_mode) - + def cancel_order_object( self, subaccount: Subaccount, cancel_order: any, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: return self.cancel_order( subaccount, @@ -227,7 +224,7 @@ def cancel_order_object( cancel_order.good_til_block_time, broadcast_mode=broadcast_mode, ) - + def transfer( self, subaccount: Subaccount, @@ -235,7 +232,7 @@ def transfer( recipient_subaccount_number: int, asset_id: int, amount: int, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: msg = self.composer.compose_msg_transfer( subaccount.address, @@ -247,13 +244,12 @@ def transfer( ) return self.send_message(subaccount, msg, broadcast_mode=broadcast_mode) - def deposit( self, subaccount: Subaccount, asset_id: int, quantums: int, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: msg = self.composer.compose_msg_deposit_to_subaccount( subaccount.address, @@ -263,13 +259,12 @@ def deposit( ) return self.send_message(subaccount, msg, broadcast_mode=broadcast_mode) - def withdraw( self, subaccount: Subaccount, asset_id: int, quantums: int, - broadcast_mode: BroadcastMode=None, + broadcast_mode: BroadcastMode = None, ) -> SubmittedTx: msg = self.composer.compose_msg_withdraw_from_subaccount( subaccount.address, @@ -278,7 +273,7 @@ def withdraw( quantums, ) return self.send_message(subaccount, msg, broadcast_mode=broadcast_mode) - + def default_broadcast_mode(self, msg: _message.Message) -> BroadcastMode: if isinstance(msg, MsgPlaceOrder): order_flags = msg.order.order_id.order_flags