Skip to content
Permalink
Browse files

Add basic tests for getting orderbook and posting order

  • Loading branch information...
officialcryptomaster committed Feb 12, 2019
1 parent 810e3f3 commit 8a07c4e7ccc88d987aa0adda085733cd0035f92b
2 .env
@@ -0,0 +1,2 @@
# env-vars required for things to work from command line and in IDE
PYTHONPATH=./src:./tests:$PYTHOPATH
@@ -3,6 +3,9 @@
*.swp
*.swo

# temp OS files
.DS_Store

# notebook checkpoints
notebooks/.ipynb_checkpoints/*

@@ -23,6 +26,5 @@ pydex.db
log/*
*.log


# Notebook starting with ZZ (test notebook etc)
ZZ*.ipynb
@@ -1,14 +1,15 @@
{
"python.envFile": "${workspaceFolder}/.env",
"python.unitTest.unittestEnabled": false,
"python.unitTest.pyTestEnabled": true,
"python.unitTest.nosetestsEnabled": false,
"python.pythonPath": "pydex_env/bin/python",
"python.pythonPath": "${workspaceFolder}/pydex_env/bin/python",
"python.linting.enabled": true,
"python.linting.lintOnSave": true,
"python.linting.pylintPath": "pydex_env/bin/pylint",
"python.linting.pylintPath": "${workspaceFolder}/pydex_env/bin/pylint",
"python.linting.pylintEnabled": true,
"python.linting.pylintArgs": ["--max-line-length", "120", "--disable", "bad-continuation"],
"python.linting.flake8Path": "pydex_env/bin/pylint",
"python.linting.flake8Path": "${workspaceFolder}/pydex_env/bin/pylint",
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": ["--max-line-length", "120"],
"python.formatting.provider": "autopep8",
@@ -46,7 +46,10 @@ Development
### Note on Contribution
While contribution to this project is highly encouraged and appreciated, I would greatly appreciate any PRs to fully adhere to the following guidelines:

1. Make sure all tests pass `<TODO(Cryptomater): actually add some tests>`
1. Make sure all tests pass
```
PYTHONPATH=./src ./pydex_env/bin/pytest
```

2. Make sure `pylint` and `flake8` do not show any issues by running:
```
@@ -6,19 +6,24 @@
"metadata": {},
"outputs": [],
"source": [
"from web3 import Web3, HTTPProvider\n",
"import binascii\n",
"import os\n",
"import binascii\n",
"from web3 import Web3, HTTPProvider\n",
"\n",
"from pydex_app.constants import NETWORK_INFO\n",
"\n",
"NETWORK_ID = os.environ.get(\"NETWORK_ID\")\n",
"PRIVATE_KEY = binascii.a2b_hex(os.environ.get(\"PRIVATE_KEY\"))\n",
"INFURA_API_KEY = os.environ['INFURA_API_KEY']\n",
"WEB3_RPC_URL = \"https://rinkeby.infura.io/\" + INFURA_API_KEY\n",
"NETWORK_ID = 4\n",
"WEB3_RPC_URL = os.environ.get(\"WEB3_RPC_URL\")\n",
"\n",
"web3_provider = HTTPProvider(WEB3_RPC_URL)\n",
"w3 = Web3(web3_provider)\n",
"acct = w3.eth.account.privateKeyToAccount(PRIVATE_KEY)\n",
"MY_ADDRESS = acct.address.lower()\n",
"MY_ADDRESS"
"print(\n",
" \"NETWORK:\", NETWORK_INFO[NETWORK_ID][\"name\"],\n",
" \"\\nRPC_URL\", WEB3_RPC_URL,\n",
" \"\\nADDRESS IN USE:\", MY_ADDRESS)"
]
},
{
@@ -28,10 +33,10 @@
"outputs": [],
"source": [
"import json\n",
"# from zero_ex.order_utils import asset_data_utils as adu\n",
"from zero_ex.order_utils import asset_data_utils as adu\n",
"\n",
"ADDRESS_BOOK = {\n",
" 4: {\n",
" \"4\": {\n",
" 'OptionsRegistry': Web3.toChecksumAddress('0xa5b14070af70f56fc0b3216045e53d3224bb0172'),\n",
" },\n",
" };\n",
@@ -84,32 +89,20 @@
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"from zero_ex.json_schemas import assert_valid\n",
"from pydex_client.client import PyDexClient\n",
"\n",
"def get_orderbook(\n",
" base_asset_data,\n",
" quote_asset_data,\n",
" full_set_asset_data=None,\n",
"client = PyDexClient(\n",
" network_id=NETWORK_ID,\n",
" page=1,\n",
" per_page=20\n",
"):\n",
" base_url = \"http://localhost:3000/v2/\"\n",
" params = dict(\n",
" baseAssetData=base_asset_data,\n",
" quoteAssetData=quote_asset_data,\n",
" networkId=network_id,\n",
" page=1,\n",
" per_page=20,\n",
" )\n",
" if full_set_asset_data:\n",
" params[\"fullSetAssetData\"] = json.dumps(full_set_asset_data)\n",
" response = requests.get(\n",
" \"{}{}\".format(base_url, \"orderbook\"),\n",
" params=params\n",
" )\n",
" return response.json()"
" web3_rpc_url=WEB3_RPC_URL,\n",
" private_key=PRIVATE_KEY,\n",
" pydex_api_url=\"http://localhost:3000\",\n",
")\n",
"\n",
"client.get_orderbook(\n",
" base_asset_data=VETH_ASSET_DATA,\n",
" quote_asset_data=LONG_ASSET_DATA,\n",
" full_set_asset_data=full_asset_set_data\n",
")"
]
},
{
@@ -119,10 +112,13 @@
"outputs": [],
"source": [
"import time\n",
"\n",
"from decimal import Decimal\n",
"from zero_ex.json_schemas import assert_valid\n",
"from pydex_app.db_models import SignedOrder\n",
"from pydex_app.utils import to_base_unit_amount\n",
"from pydex_app.config import NULL_ADDRESS\n",
"from decimal import Decimal\n",
"\n",
"\n",
"def make_signed_order(\n",
" asset,\n",
@@ -203,7 +199,7 @@
" \"{}{}\".format(base_url, \"order\"),\n",
" json=order.to_json()\n",
" )\n",
" return response.json()"
" return response"
]
},
{
@@ -230,7 +226,7 @@
"from pydex_app.db_models import SignedOrder\n",
"from pprint import pprint\n",
"\n",
"orderbook = get_orderbook(\n",
"orderbook = client.get_orderbook(\n",
" base_asset_data=VETH_ASSET_DATA,\n",
" quote_asset_data=LONG_ASSET_DATA,\n",
" full_set_asset_data=full_asset_set_data\n",
@@ -251,6 +247,20 @@
"bids, asks = print_order_book(orderbook)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"make_signed_order(\n",
" asset=\"LONG\",\n",
" qty=0.0001,\n",
" price=0.45,\n",
" side=\"BUY\",\n",
" ).to_json()"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -267,7 +277,17 @@
" side=side,\n",
" )\n",
" print(json.dumps(order.to_json(include_hash=True)))\n",
" print(sign_and_post_order(order))"
" res = sign_and_post_order(order)\n",
" print(res)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"res.json()"
]
},
{
@@ -337,124 +357,6 @@
"res = owc._rpc(method=\"GET_STATS\")\n",
"res"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for side in [\"BUY\", \"SELL\"]:\n",
" order = make_signed_order(\n",
" asset=\"LONG\",\n",
" qty=0.0001,\n",
" price=0.45,\n",
" side=side,\n",
" )\n",
" print(json.dumps(order.to_json(include_hash=True)))\n",
" print(sign_and_post_order(order))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from web3 import Web3\n",
"from zero_ex.contract_artifacts import abi_by_name;\n",
"\n",
"\n",
"class TradeExecutor:\n",
" def __init__(self, address, private_key, rpc_url, network_id, exchange_address):\n",
" # Fee recipient address and private key\n",
" self.address = address\n",
" self.private_key = private_key\n",
" # Initialize web3\n",
" self.w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={\"timeout\": 60}))\n",
" # Initalize zrx_exchange contract\n",
" self.zrx_exchange = self.w3.eth.contract(\n",
" address=exchange_address,\n",
" abi=abi_by_name(\"exchange\"),\n",
" )\n",
" # Initialize chainId\n",
" self.network_id = network_id\n",
"\n",
" def execute_batch_fill_or_kill(\n",
" self, orders, taker_asset_fill_amounts, signatures\n",
" ):\n",
" print(orders)\n",
" print(taker_asset_fill_amounts)\n",
" print(signatures)\n",
" function = self.zrx_exchange.functions.batchFillOrKillOrders(\n",
" orders=orders,\n",
" takerAssetFillAmounts=taker_asset_fill_amounts,\n",
" signatures=signatures,\n",
" ).call()\n",
" return self._build_and_send_tx(function)\n",
"\n",
" def _get_tx_params(self, value=0, gas=150000):\n",
" # Get generic transcation parameters.\n",
" return {\n",
" \"chainId\": self.network_id,\n",
" \"from\": self.address,\n",
" \"value\": value,\n",
" \"gas\": gas,\n",
" \"nonce\": self.w3.eth.getTransactionCount(self.address)\n",
" }\n",
"\n",
" def _build_and_send_tx(function):\n",
" # Build and send a transaction to the zrx_exchange\n",
" tx_params = _get_tx_params()\n",
" transaction = function.buildTransaction(tx_params)\n",
" signed_tx = self.w3.eth.account.signTransaction(\n",
" transaction, private_key = self.private_key\n",
" )\n",
" return self.w3.eth.sendRawTransaction(signed_tx.sendRawTransaction)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"buy = bids[0]\n",
"sell = asks[0]\n",
"buy_json = {k: v for k, v in buy.to_json().items() if k not in [\"exchangeAddress\", \"signature\"]}\n",
"sell_json = {k: v for k, v in sell.to_json().items() if k not in [\"exchangeAddress\", \"signature\"]}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tx = TradeExecutor(\n",
" address=Web3.toChecksumAddress(MY_ADDRESS),\n",
" private_key=PRIVATE_KEY,\n",
" rpc_url=WEB3_RPC_URL,\n",
" network_id=NETWORK_ID,\n",
" exchange_address=Web3.toChecksumAddress(\"0xbce0b5f6eb618c565c3e5f5cd69652bbc279f44e\"),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"res = tx.execute_batch_fill_or_kill(\n",
" orders=[buy_json, sell_json],\n",
" taker_asset_fill_amounts=[buy.maker_asset_amount, sell.taker_asset_amount], \n",
" signatures=[buy.signature, sell.signature],\n",
")\n",
"res"
]
}
],
"metadata": {
@@ -12,8 +12,9 @@
class PydexBaseConfig: # pylint: disable=too-few-public-methods
"""Base configuration class for pyDEX App"""
SECRET_KEY = os.environ.get("SECRET_KEY", "development secret key is not safe")
SQLALCHEMY_DATABASE_URI = "sqlite:///../../pydex.db"
SQLALCHEMY_DATABASE_URI = "sqlite:///{}../../pydex.db".format(os.getcwd())
SQLALCHEMY_TRACK_MODIFICATIONS = False
TESTING = False
# PYDEX EXCHANGE PARAMS
PYDEX_NETWORK_ID = RINKEBY_NETWORK_ID
PYDEX_ZRX_FEE_RECIPIENT = NULL_ADDRESS
@@ -16,3 +16,22 @@
RINKEBY_NETWORK_ID = "4"
KOVAN_NETWORK_ID = "42"
GANACHE_NETWORK_ID = "50"

NETWORK_INFO = {
MAIN_NETWORK_ID: {
"name": "main",
# "exchange_id": "",
},
RINKEBY_NETWORK_ID: {
"name": "rinkeby",
"exchange_id": "0xbce0b5f6eb618c565c3e5f5cd69652bbc279f44e",
},
KOVAN_NETWORK_ID: {
"name": "kovan",
# "exchange_id": "",
},
GANACHE_NETWORK_ID: {
"name": "ganache",
# "exchange_id": "",
},
}
@@ -1,6 +1,15 @@
"""
OrderWatcherClient is the client responsible for registering orders with the
0x order-watcher server
0x order-watcher server.
For this client to work, there needs to be an order-watcher server running.
The easiest way to run the server is using the `start-order-watcher` which is
provided with this project.
It is also possible to run the server as a Docker image using:
`docker run -ti -p 8080:8080 -e JSON_RPC_URL=https://mainnet.infura.io \\`
`-e NETWORK_ID=1 0xorg/order-watcher`
You can test that the service is running with
`wscat -c ws://0.0.0.0:8080`
author: officialcryptomaster@gmail.com
"""
Oops, something went wrong.

0 comments on commit 8a07c4e

Please sign in to comment.
You can’t perform that action at this time.