dYdX Python API for Limit Orders
The library is currently tested against Python versions 2.7, 3.4, 3.5, and 3.6
Installation
dydx-python
is available on PyPI. Install with pip
:
pip install dydx-python
Documentation
Check the dYdX developer docs for the API endpoint.
Example Usage
Initializing the client
from dydx.client import Client
import dydx.constants as consts
import dydx.util as utils
# create a new client with a private key (string or bytearray)
client = Client(
private_key='0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d',
node='https://mainnet.infura.io/v3/00000000000000000000000000000000'
)
HTTP API Calls
Trading Pairs
# Get all trading pairs for dydx
pairs = client.get_pairs()
Account Balances
# Get my account balances of margin-trading accounts
my_balances = client.get_my_balances()
# Get my account balances of perpetual accounts
balances = client.get_my_perpetual_balances()
Open Orders
# Get orders created by my account for both sides of the book
my_orders = client.get_my_orders(
market=['WETH-DAI', 'DAI-WETH'],
limit=None,
startingBefore=None
)
# Get all orders for both sides of the book
ten_days_ago = datetime.datetime.now() - datetime.timedelta(days=10)
all_orders = client.get_orders(
market=['WETH-DAI', 'DAI-WETH'],
makerAccountOwner=None, # optional
makerAccountNumber=None, # optional
limit=2, # optional
startingBefore=ten_days_ago # optional
)
Historical Fills
# Get fills created by my account for both sides of the orderbook
my_fills = client.get_my_fills(
market=['WETH-DAI', 'DAI-WETH'],
limit=None, # optional
startingBefore=None # optional
)
# Get all fills from one side of the book
all_fills = client.get_fills(
market=['WETH-DAI'], # 'DAI-WETH' side of the book is not included
makerAccountOwner='0x5F5A46a8471F60b1E9F2eD0b8fc21Ba8b48887D8', # optional
makerAccountNumber=0, # optional
limit=2, # optional
startingBefore=None # optional
)
'''
fills = {
"fills": [
{
uuid: "b53ab8c4-465f-4950-add2-dd807c048d68",
createdAt: "2020-03-08T17:42:36.037Z",
transactionHash: "0x39576745c2f030ba04bf4df7bcc64ffaa97421243c53e714bca4161163be9d51",
status: "PENDING",
market: "WETH-DAI",
side: "BUY",
feeAmount: "0",
orderClientId: null,
price: "217.019",
amount: "15000000000000000000",
orderId: "0x8924cdc0d18899d250bfa27d5929967e26e7e676745a28b6ee5b3a8f182ceb9f",
accountOwner: "0x8a9d46d28003673cd4fe7a56ecfcfa2be6372e64",
accountNumber: "63397253610709255086306580859198088914565604507660670583302927962305720029570",
liquidity: "TAKER"
},
...
]
}
'''
# Get one order by id
order = client.get_order(
orderId,
)
'''
order = {
"order" = {
"uuid": "c95c386a-307d-4fbf-bcac-a7ff965a7207",
"id": "0x812f2e71081daa820d08fa25c76c06332cd39282433679a413c03c5d4591bc35",
"clientId": "d046f4db-12a9-48fb-b413-6916a9f0cfff",
"status": "CANCELED",
"accountOwner": "0x862821badb9c5800654015ba9a2d9d7894c83a7a",
"accountNumber": "0",
"orderType": "LIMIT",
"fillOrKill": false,
"postOnly": false,
"triggerPrice": null,
"market": "WETH-DAI",
"side": "BUY",
"baseAmount": "186056800000000000000",
"quoteAmount": "39808712928000001179648",
"filledAmount": "0",
"price": "213.96",
"cancelReason": "USER_CANCELED",
"createdAt": "2020-03-08T17:35:24.694Z",
"updatedAt": "2020-03-08T17:35:25.474Z",
"expiresAt": "2020-03-08T17:55:29.000Z"
}
}
'''
Historical Trades
# Get trades created by my account for both sides of the orderbook
my_trades = client.get_my_trades(
market=['WETH-DAI', 'DAI-WETH'],
limit=None, # optional
startingBefore=None # optional
)
# Get all trades from one side of the book
all_trades = client.get_trades(
market=['WETH-DAI'], # 'DAI-WETH' side of the book is not included
makerAccountOwner='0x5F5A46a8471F60b1E9F2eD0b8fc21Ba8b48887D8', # optional
makerAccountNumber=0, # optional
limit=2, # optional
startingBefore=None # optional
)
'''
trades = {
"trades": [
{
"uuid": "7b00efba-5002-4562-b777-0122ede33fec",
"createdAt": "2020-03-08T17:32:35.413Z",
"transactionHash": "0xfd6fe9605114a5d44000b51d126751eee1f38866ebd4d4be7eacf89d8bf264d9",
"status": "CONFIRMED",
"market": "WETH-DAI",
"side": "SELL",
"price": "214.90",
"amount": "2447332508052454104",
"makerOrderId": "0x9e5cf0e5091566651ad33c56fb4e24ce96341b561d31180f0d471163709b098d",
"makerAccountOwner": "0x862821badb9c5800654015ba9a2d9d7894c83a7a",
"makerAccountNumber": "0",
"takerOrderId": "0xc1a71851c62fc132ece0060c46a076cb082741ef6b80f894b20c4351b824dfb7",
"takerAccountOwner": "0xd3069c9e486a8b77add55ae3ceb3a4b138fb76c7",
"takerAccountNumber": "48394678789855236190833155557217125360276244141304950018155758748772338730587"
},
...
]
}
'''
Create an Order (Perp)
# Create order to LONG ETH with an order quantity of 2,500 ETH-USD contracts
# at a price of 250 USD per ETH.
created_order = client.place_order(
market=consts.PAIR_WETH_PUSD,
side=consts.SIDE_SELL,
amount=utils.usd_to_order_amount(25000),
price=Decimal('250e-12'),
fillOrKill=False,
postOnly=False
)
# Create order to BUY 10 PBTC for 723,400.00 USDC (a price of 7234.00 PBTC/USDC)
created_order = client.place_order(
market=consts.PAIR_PBTC_USDC,
side=consts.SIDE_BUY,
amount=utils.btc_to_sats(10),
price=Decimal('72.34'),
fillOrKill=False,
postOnly=False
)
# Create order to BUY 100 PLINK for 1,500.00 USDC (a price of 15.00 PLINK/USDC)
created_order = client.place_order(
market=consts.PAIR_PLINK_USDC,
side=consts.SIDE_BUY,
amount=utils.link_to_order_amount(100),
price=Decimal('15.00'),
fillOrKill=False,
postOnly=False
)
Create an Order (Solo)
# Create order to BUY 10 ETH for 2504.90 DAI (a price of 250.49 DAI/ETH)
created_order = client.place_order(
market=consts.PAIR_WETH_DAI,
side=consts.SIDE_BUY,
amount=utils.token_to_wei(10, consts.MARKET_WETH),
price=Decimal('250.49'),
fillOrKill=False,
postOnly=False
)
# Create order to SELL 10 ETH for 1500.10 USDC (a price of 150.01 USDC/ETH)
# 'e-12' is in the price since USDC has 6 decimal places (ETH and DAI have 18)
created_order = client.place_order(
market=consts.PAIR_WETH_USDC,
side=consts.SIDE_SELL,
amount=utils.token_to_wei(10, consts.MARKET_WETH),
price=Decimal('150.01e-12'),
fillOrKill=False,
postOnly=False
)
Cancel an Order
# Cancel the previously created solo order
order_hash = created_order['order']['id']
canceled_order = client.cancel_order(
hash=order_hash
)
# Cancel the previously created perpetual order
order_hash = created_order['order']['id']
canceled_order = client.cancel_perpetual_order(
hash=order_hash
)
Get Orderbook
orderbook = client.get_orderbook(
market='WETH-DAI'
)
'''
orderbook = {
"bids": [
{
"id": "0xefa4562c0747a8f2a9aa69abb817474ee9e98c8505a71de6054a610ac744b0cd",
"uuid": "c58be890-6e76-4e98-95d4-27977a91af19",
"amount": "17459277053478281216",
"price": "160.08"
},
{
"id": "0xa2ab9f653106fefef5b1264a509b02eab021ffea442307e995908e5360f3cd4d",
"uuid": "d2dba4c6-6442-46bc-b097-1f37312cf279",
"amount": "149610989871929360384",
"price": "160.07"
},
{
"id": "0xec35d60dd1c5eab86cd7881fcbc1239193ceda695df2815d521a46f54bd90580",
"uuid": "24d5a4e1-195b-43fa-a7d8-1d794619e97e",
"amount": "54494000000000000000",
"price": "160.06"
},
],
"asks": [
{
"id": "0xb242e2006a0d99c390fc7256d10558844a719d580e80eaa5a4f99dd14bd9ce5e",
"uuid": "6fdff2f3-0175-4297-bf23-89526eb9aa36",
"amount": "12074182754430260637",
"price": "160.30"
},
{
"id": "0xe32a00e11b91b6f8daa70fbe03ad0100fa458c0d87e5c59f2e629ce9d5d32921",
"uuid": "3f9b35a8-d843-4ae6-bc8b-b534b07e8093",
"amount": "50000000000000000000",
"price": "160.40"
},
{
"id": "0xcad0c2e92094bd1dd17a694bd25933a8825c6014aaf4ae2925512f62c15ae968",
"uuid": "5aefdfd2-4e4d-4b37-9c99-35e8eec0ed9a",
"amount": "50000000000000000000",
"price": "160.50"
},
]
}
'''
Get Solo Market
market = client.get_market(
market='WETH-DAI'
)
'''
market = {
"market": {
"WETH-DAI": {
"name": "WETH-DAI",
"baseCurrency": {
"currency": "WETH",
"decimals": 18,
"soloMarketId": 0,
},
"quoteCurrency": {
"currency": "DAI",
"decimals": 18,
"soloMarketId": 3,
},
"minimumTickSize": "0.01",
"minimumOrderSize": "100000000000000000",
"smallOrderThreshold": "500000000000000000",
"makerFee": "0",
"largeTakerFee": "0.005",
"smallTakerFee": "0.0015",
},
}
}
'''
Get Solo Markets
markets = client.get_markets()
'''
markets = {
"markets": {
"WETH-DAI": {
"name": "WETH-DAI",
"baseCurrency": {
"currency": "WETH",
"decimals": 18,
"soloMarketId": 0,
},
"quoteCurrency": {
"currency": "DAI",
"decimals": 18,
"soloMarketId": 3,
},
"minimumTickSize": "0.01",
"minimumOrderSize": "100000000000000000",
"smallOrderThreshold": "500000000000000000",
"makerFee": "0",
"largeTakerFee": "0.005",
"smallTakerFee": "0.0015",
},
"WETH-USDC": {
"name": "WETH-USDC",
"baseCurrency": {
"currency": "WETH",
"decimals": 18,
"soloMarketId": 0,
},
"quoteCurrency": {
"currency": "USDC",
"decimals": 6,
"soloMarketId": 2,
},
"minimumTickSize": "0.00000000000001",
"minimumOrderSize": "100000000000000000",
"smallOrderThreshold": "500000000000000000",
"makerFee": "0",
"largeTakerFee": "0.005",
"smallTakerFee": "0.0015",
},
"DAI-USDC": {
"name": "DAI-USDC",
"baseCurrency": {
"currency": "DAI",
"decimals": 18,
"soloMarketId": 3,
},
"quoteCurrency": {
"currency": "USDC",
"decimals": 6,
"soloMarketId": 1,
},
"minimumTickSize": "0.0000000000000001",
"minimumOrderSize": "20000000000000000000",
"smallOrderThreshold": "100000000000000000000",
"makerFee": "0",
"largeTakerFee": "0.005",
"smallTakerFee": "0.0005",
},
}
}
'''
Get Perpetual Market
market = client.get_perpetual_market(
market='PBTC-USDC'
)
'''
market = {
"market": {
"uuid": "f6d20698-32ac-4f3a-a9c4-b6b7528b7b94",
"market": "PBTC-USDC",
"oraclePrice": "68.9615",
"fundingRate": "0",
"minCollateral": "0.1075",
"globalIndexValue": "0",
"globalIndexTimestamp": "1587407069",
"createdAt": "2020-04-09T22:42:35.696Z",
"updatedAt": "2020-04-20T18:48:06.334Z"
}
}
'''
Get Perpetual Markets
markets = client.get_perpetual_markets()
'''
markets = {
"markets": [
{
"uuid": "f6d20698-32ac-4f3a-a9c4-b6b7528b7b94",
"market": "PBTC-USDC",
"oraclePrice": "68.9615",
"fundingRate": "0",
"minCollateral": "0.1075",
"globalIndexValue": "0",
"globalIndexTimestamp": "1587407069",
"createdAt": "2020-04-09T22:42:35.696Z",
"updatedAt": "2020-04-20T18:47:06.197Z"
}
]
}
'''
Perpetuals
Deposit / Withdraw
# deposit 2 ETH into the ETH-USD Perpetual
tx_hash = client.eth.perp.deposit(
market=consts.PAIR_WETH_PUSD,
amount=utils.token_to_wei(2, consts.MARKET_WETH)
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw 1 ETH from the ETH-USD Perpetual
tx_hash = client.eth.perp.withdraw(
market=consts.PAIR_WETH_PUSD,
amount=utils.token_to_wei(1, consts.MARKET_WETH)
)
receipt = client.eth.get_receipt(tx_hash)
# deposit 100 USDC into the BTC-USD Perpetual
tx_hash = client.eth.perp.set_allowance(consts.PAIR_PBTC_USDC) # must only be called once, ever
receipt = client.eth.get_receipt(tx_hash)
tx_hash = client.eth.perp.deposit(
market=consts.PAIR_PBTC_USDC,
amount=utils.token_to_wei(100, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw 50 USDC from the BTC-USD Perpetual
tx_hash = client.eth.perp.withdraw(
market=consts.PAIR_PBTC_USDC,
amount=utils.token_to_wei(50, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
# deposit 100 USDC into the LINK-USD Perpetual
tx_hash = client.eth.perp.set_allowance(consts.PAIR_PLINK_USDC) # must only be called once, ever
receipt = client.eth.get_receipt(tx_hash)
tx_hash = client.eth.perp.deposit(
market=consts.PAIR_PLINK_USDC,
amount=utils.token_to_wei(100, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw 50 USDC from the LINK-USD Perpetual
tx_hash = client.eth.perp.withdraw(
market=consts.PAIR_PLINK_USDC,
amount=utils.token_to_wei(50, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
Getters
# get the USD value of PBTC
# Since PBTC is measured in Satoshis (1e-8 of one BTC) and USDC has 6 decimal places,
# a normal price of $7200 per BTC would return a result of 72.
btc_price = client.eth.perp.get_oracle_price(
market=consts.PAIR_PBTC_USDC
)
# get the USD value of PLINK
# Since PLINK and USDC both have 6 decimal places,
# a normal price of $15 per LINK would return a result of 15.
btc_price = client.eth.perp.get_oracle_price(
market=consts.PAIR_PLINK_USDC
)
# get the ETH value of USD
# Since USD is considered to have 6 decimal places, and ETH has 18 decimals places,
# a normal price of $250 per ETH would have a price of 1 / (250e-12).
eth_price = client.eth.perp.get_oracle_price(
market=consts.PAIR_WETH_PUSD
)
Solo (ETH trading)
Deposit / Withdraw
# deposit 10 ETH
# does not require set_allowance
tx_hash = client.eth.solo.deposit(
market=consts.MARKET_WETH,
wei=utils.token_to_wei(10, consts.MARKET_WETH)
)
receipt = client.eth.get_receipt(tx_hash)
# deposit 10 WETH ERC20 tokens without using the WETH payable proxy address
# requires set_allowance
tx_hash = client.eth.solo.deposit(
market=consts.MARKET_WETH,
wei=utils.token_to_wei(10, consts.MARKET_WETH),
asEth=False
)
receipt = client.eth.get_receipt(tx_hash)
# deposit 100 DAI
tx_hash = client.eth.solo.set_allowance(market=consts.MARKET_DAI) # must only be called once, ever
receipt = client.eth.get_receipt(tx_hash)
tx_hash = client.eth.solo.deposit(
market=consts.MARKET_DAI,
wei=utils.token_to_wei(100, consts.MARKET_DAI)
)
receipt = client.eth.get_receipt(tx_hash)
# deposit 100 USDC
tx_hash = client.eth.solo.set_allowance(market=consts.MARKET_USDC) # must only be called once, ever
receipt = client.eth.get_receipt(tx_hash)
tx_hash = client.eth.solo.deposit(
market=consts.MARKET_USDC,
wei=utils.token_to_wei(100, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw 10 WETH ERC20 tokens without using the WETH payable proxy address
tx_hash = client.eth.solo.deposit(
market=consts.MARKET_WETH,
wei=utils.token_to_wei(10, consts.MARKET_WETH),
asEth=False
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw 50 USDC
tx_hash = client.eth.solo.withdraw(
market=consts.MARKET_USDC,
wei=utils.token_to_wei(50, consts.MARKET_USDC)
)
receipt = client.eth.get_receipt(tx_hash)
# withdraw all DAI (including interest)
tx_hash = client.eth.solo.withdraw_to_zero(market=consts.MARKET_DAI)
receipt = client.eth.get_receipt(tx_hash)
Getters
# get the USD value of one atomic unit of DAI
dai_price = client.eth.solo.get_oracle_price(consts.MARKET_DAI)
# get dYdX balances
balances = client.eth.solo.get_my_balances()
'''
balances = [
-91971743707894,
3741715702031854553560,
2613206278
]
'''
# get dYdX account collateralization
collateralization = client.eth.get_my_collateralization()
'''
collateralization = 2.5 or float('inf')
'''
# collateralization must remain above the minimum to prevent liquidation
assert(collateralization > consts.MINIMUM_COLLATERALIZATION)
'''
consts.MINIMUM_COLLATERALIZATION = 1.15
'''
General Ethereum Getters
Getting information directly from the blockchain by querying a node
# get Wallet balances
balance = client.eth.get_my_wallet_balance(consts.MARKET_DAI)
'''
balance = 1000000000000000000
'''
## Testing
Install the requirements
pip install -r requirements.txt
Run the tests
docker-compose up tox