Repository: Polymarket/py-clob-client
Branch: main
Commit: cc1740c11adf
Files: 110
Total size: 365.5 KB
Directory structure:
gitextract_cz0xsyu3/
├── .editorconfig
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ ├── release.yaml
│ └── workflow.yaml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── examples/
│ ├── GTD_order.py
│ ├── are_orders_scoring.py
│ ├── cancel_all.py
│ ├── cancel_market_orders.py
│ ├── cancel_order.py
│ ├── cancel_orders.py
│ ├── create_api_key.py
│ ├── create_readonly_api_key.py
│ ├── delete_readonly_api_key.py
│ ├── derive_api_key.py
│ ├── drop_notifications.py
│ ├── get_api_keys.py
│ ├── get_balance_allowance.py
│ ├── get_builder_trades.py
│ ├── get_closed_only_mode.py
│ ├── get_last_trade_price.py
│ ├── get_last_trades_prices.py
│ ├── get_market_trades_events.py
│ ├── get_markets.py
│ ├── get_mid_market_price.py
│ ├── get_mid_markets_prices.py
│ ├── get_notifications.py
│ ├── get_ok.py
│ ├── get_open_orders_with_readonly_key.py
│ ├── get_order.py
│ ├── get_orderbook.py
│ ├── get_orderbooks.py
│ ├── get_orders.py
│ ├── get_price.py
│ ├── get_prices.py
│ ├── get_readonly_api_keys.py
│ ├── get_server_time.py
│ ├── get_spread.py
│ ├── get_spreads.py
│ ├── get_trades.py
│ ├── is_order_scoring.py
│ ├── market_buy_order.py
│ ├── market_sell_order.py
│ ├── order.py
│ ├── orders.py
│ ├── place_builder_order.py
│ ├── post_heartbeat.py
│ ├── post_only_order.py
│ ├── rfq_accept_quote.py
│ ├── rfq_approve_order.py
│ ├── rfq_cancel_quote.py
│ ├── rfq_cancel_request.py
│ ├── rfq_config.py
│ ├── rfq_create_quote.py
│ ├── rfq_create_request.py
│ ├── rfq_full_flow.py
│ ├── rfq_get_best_quote.py
│ ├── rfq_get_quotes.py
│ ├── rfq_get_requests.py
│ └── update_balance_allowance.py
├── py_clob_client/
│ ├── __init__.py
│ ├── client.py
│ ├── clob_types.py
│ ├── config.py
│ ├── constants.py
│ ├── endpoints.py
│ ├── exceptions.py
│ ├── headers/
│ │ ├── __init__.py
│ │ └── headers.py
│ ├── http_helpers/
│ │ ├── __init__.py
│ │ └── helpers.py
│ ├── order_builder/
│ │ ├── __init__.py
│ │ ├── builder.py
│ │ ├── constants.py
│ │ └── helpers.py
│ ├── rfq/
│ │ ├── __init__.py
│ │ ├── rfq_client.py
│ │ ├── rfq_helpers.py
│ │ └── rfq_types.py
│ ├── signer.py
│ ├── signing/
│ │ ├── __init__.py
│ │ ├── eip712.py
│ │ ├── hmac.py
│ │ └── model.py
│ └── utilities.py
├── requirements.txt
├── setup.py
└── tests/
├── __init__.py
├── headers/
│ ├── __init__.py
│ └── test_headers.py
├── http_helpers/
│ ├── __init__.py
│ └── test_helpers.py
├── order_builder/
│ ├── __init__.py
│ ├── test_builder.py
│ └── test_helpers.py
├── rfq/
│ ├── test_rfq_payload.py
│ └── test_rfq_query_params.py
├── signing/
│ ├── __init__.py
│ ├── test_eip712.py
│ └── test_hmac.py
└── test_utilities.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
[*.{py}]
indent_style = space
indent_size = 4
[*.json]
indent_style = space
indent_size = 2
[*.yaml]
indent_style = space
indent_size = 2
quote_type = single
================================================
FILE: .github/CODEOWNERS
================================================
# All PRs on any file must be reviewed by one of the following team members
# Wildcard (*) for all files
* @Polymarket/eng-platform
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socioeconomic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [`liam@polymarket.com`](mailto:liam@polymarket.com). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: .github/CONTRIBUTING.md
================================================
## python-order-utils Monorepo Contribution Guide
All contributions to the python-order-utils are welcome and greatly appreciated! This document serves to outline the process for contributions and help you get set up.
### Steps to get started
1. Fork 'Polymarket/python-order-utils'
2. Clone your fork
3. Follow the [installation instructions](./README.md) in the monorepo's top level README.
4. Open pull requests with the `[WIP]` flag against the `main` branch and include a description of the intended change in the PR description.
Before removing the `[WIP]` tag and submitting a PR for review, make sure that:
- it passes our linter checks
- the test suite passes for all packages
- it passes our continuous integration tests
- your fork is up to date with `main`
### Branch structure & naming
Our main branch, `main`, represents the current development state of the codebase. All pull requests should be opened against `main`.
Name your branch with the format `{fix | feat | refactor | chore }/{ description }`
- A `fix` addresses a bug or other issue
- A `feat` adds new functionality/interface surface area
- A `refactor` changes no business logic or interfaces, but improves implementation
- A `chore` addresses minor improvements or configuration changes
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## Overview
## Description
## Notes
## Action items
- [ ] Tag issue (bug, enhancement, feature, etc.)
- [ ] Initial discussion/assign team member
- [ ] Move discussion to PR if necessary and when ready
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Overview
## Description
## Testing instructions
## Types of changes
- [ ] Refactor/enhancement
- [ ] Bug fix/behavior correction
- [ ] New feature
- [ ] Breaking change
- [ ] Other, additional
## Notes
## Status
- [ ] Prefix PR title with `[WIP]` if necessary (changes not yet made).
- [ ] Add tests to cover changes as needed.
- [ ] Update documentation/changelog as needed.
- [ ] Verify all tests run correctly in CI and pass.
- [ ] Ready for review/merge.
================================================
FILE: .github/workflows/release.yaml
================================================
name: Release
on:
release:
types: [published]
permissions:
id-token: write
jobs:
release:
name: release
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: 3.9
- run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e .
- name: Run Tests
run: make test
# If your build system reads version dynamically, set it here.
# Common pattern: setuptools-scm or hatch-vcs will pick up the git tag automatically.
- name: Install build tooling
run: |
pip install build
- name: Build sdist and wheel
env:
# Many tools will respect this if you wire it up (optional)
PACKAGE_VERSION: ${{ github.ref_name }}
run: python -m build
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
================================================
FILE: .github/workflows/workflow.yaml
================================================
name: Test
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pull-requests: read
jobs:
build-lint-test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: 3.9
- run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e .
- name: Run Tests
run: make test
================================================
FILE: .gitignore
================================================
.idea/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
================================================
FILE: CONTRIBUTING.md
================================================
### Contributing
Thanks for helping improve `py-clob-client`.
- Fork the repo and create a feature branch.
- Create focused edits with tests where applicable.
- Run the examples to sanity‑check trading flows against a sandbox.
- Open a PR with a clear description of the change and motivation.
For security issues, please see `SECURITY.md`.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 Polymarket
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
init:
pip install -r requirements.txt
test:
pytest -s
fmt:
black ./.
================================================
FILE: README.md
================================================
# Polymarket Python CLOB Client
Python client for the Polymarket Central Limit Order Book (CLOB).
## Documentation
## Installation
```bash
# install from PyPI (Python 3.9>)
pip install py-clob-client
```
## Usage
The examples below are short and copy‑pasteable.
- What you need:
- **Python 3.9+**
- **Private key** that owns funds on Polymarket
- Optional: a **proxy/funder address** if you use an email or smart‑contract wallet
- Tip: store secrets in environment variables (e.g., with `.env`)
### Quickstart (read‑only)
```python
from py_clob_client.client import ClobClient
client = ClobClient("https://clob.polymarket.com") # Level 0 (no auth)
ok = client.get_ok()
time = client.get_server_time()
print(ok, time)
```
### Start trading (EOA)
**Note**: If using MetaMask or hardware wallet, you must first set token allowances. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below.
```python
from py_clob_client.client import ClobClient
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
FUNDER = ""
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
```
### Start trading (proxy wallet)
For email/Magic or browser wallet proxies, you need to specify two additional parameters:
#### Funder Address
The **funder address** is the actual address that holds your funds on Polymarket. When using proxy wallets (email wallets like Magic or browser extension wallets), the signing key differs from the address holding the funds. The funder address ensures orders are properly attributed to your funded account.
#### Signature Types
The **signature_type** parameter tells the system how to verify your signatures:
- `signature_type=0` (default): Standard EOA (Externally Owned Account) signatures - includes MetaMask, hardware wallets, and any wallet where you control the private key directly
- `signature_type=1`: Email/Magic wallet signatures (delegated signing)
- `signature_type=2`: Browser wallet proxy signatures (when using a proxy contract, not direct wallet connections)
```python
from py_clob_client.client import ClobClient
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
PROXY_FUNDER = "" # Address that holds your funds
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=PROXY_FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
```
### Find markets, prices, and orderbooks
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
client = ClobClient("https://clob.polymarket.com") # read-only
token_id = "" # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
mid = client.get_midpoint(token_id)
price = client.get_price(token_id, side="BUY")
book = client.get_order_book(token_id)
books = client.get_order_books([BookParams(token_id=token_id)])
print(mid, price, book.market, len(books))
```
### Place a market order (buy by $ amount)
**Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below.
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import MarketOrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
FUNDER = ""
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
mo = MarketOrderArgs(token_id="", amount=25.0, side=BUY, order_type=OrderType.FOK) # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
signed = client.create_market_order(mo)
resp = client.post_order(signed, OrderType.FOK)
print(resp)
```
### Place a limit order (shares at a price)
**Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below.
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
FUNDER = ""
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
order = OrderArgs(token_id="", price=0.01, size=5.0, side=BUY) # Get a token ID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
signed = client.create_order(order)
resp = client.post_order(signed, OrderType.GTC)
print(resp)
```
### Manage orders
**Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below.
```python
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OpenOrderParams
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
FUNDER = ""
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
open_orders = client.get_orders(OpenOrderParams())
order_id = open_orders[0]["id"] if open_orders else None
if order_id:
client.cancel(order_id)
client.cancel_all()
```
### Markets (read‑only)
```python
from py_clob_client.client import ClobClient
client = ClobClient("https://clob.polymarket.com")
markets = client.get_simplified_markets()
print(markets["data"][:1])
```
### User trades (requires auth)
**Note**: EOA/MetaMask users must set token allowances before trading. See [Token Allowances section](#important-token-allowances-for-metamaskeoa-users) below.
```python
from py_clob_client.client import ClobClient
HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = ""
FUNDER = ""
client = ClobClient(
HOST, # The CLOB API endpoint
key=PRIVATE_KEY, # Your wallet's private key
chain_id=CHAIN_ID, # Polygon chain ID (137)
signature_type=1, # 1 for email/Magic wallet signatures
funder=FUNDER # Address that holds your funds
)
client.set_api_creds(client.create_or_derive_api_creds())
last = client.get_last_trade_price("")
trades = client.get_trades()
print(last, len(trades))
```
## Important: Token Allowances for MetaMask/EOA Users
### Do I need to set allowances?
- **Using email/Magic wallet?** No action needed - allowances are set automatically.
- **Using MetaMask or hardware wallet?** You need to set allowances before trading.
### What are allowances?
Think of allowances as permissions. Before Polymarket can move your funds to execute trades, you need to give the exchange contracts permission to access your USDC and conditional tokens.
### Quick Setup
You need to approve two types of tokens:
1. **USDC** (for deposits and trading)
2. **Conditional Tokens** (the outcome tokens you trade)
Each needs approval for the exchange contracts to work properly.
### Setting Allowances
Here's a simple breakdown of what needs to be approved:
**For USDC (your trading currency):**
- Token: `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`
- Approve for these contracts:
- `0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E` (Main exchange)
- `0xC5d563A36AE78145C45a50134d48A1215220f80a` (Neg risk markets)
- `0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296` (Neg risk adapter)
**For Conditional Tokens (your outcome tokens):**
- Token: `0x4D97DCd97eC945f40cF65F87097ACe5EA0476045`
- Approve for the same three contracts above
### Example Code
See [this Python example](https://gist.github.com/poly-rodr/44313920481de58d5a3f6d1f8226bd5e) for setting allowances programmatically.
**Pro tip**: You only need to set these once per wallet. After that, you can trade freely.
## Notes
- To discover token IDs, use the Markets API Explorer: [Get Markets](https://docs.polymarket.com/developers/gamma-markets-api/get-markets).
- Prices are in dollars from 0.00 to 1.00. Shares are whole or fractional units of the outcome token.
See [/example](/examples) for more.
================================================
FILE: SECURITY.md
================================================
### Security
If you believe you’ve found a security vulnerability, please email security@polymarket.com. Do not open a public issue.
Include:
- A description of the issue and potential impact
- Steps to reproduce or a minimal proof of concept
- Any relevant logs or environment details
We will acknowledge receipt, investigate, and provide guidance on next steps.
================================================
FILE: examples/GTD_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderArgs, OrderType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Create and sign a limit order buying 100 YES tokens for 0.50c each
order_args = OrderArgs(
price=0.50,
size=100.0,
side=BUY,
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
expiration="1000000000000",
)
signed_order = client.create_order(order_args)
resp = client.post_order(signed_order, OrderType.GTD)
print(resp)
print("Done!")
main()
================================================
FILE: examples/are_orders_scoring.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrdersScoringParams
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
scoring = client.are_orders_scoring(
OrdersScoringParams(
orderIds=[
"0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc"
]
)
)
print(scoring)
print("Done!")
main()
================================================
FILE: examples/cancel_all.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.cancel_all()
print(resp)
print("Done!")
main()
================================================
FILE: examples/cancel_market_orders.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.cancel_market_orders(market="0xaaa", asset_id="100")
print(resp)
print("Done!")
main()
================================================
FILE: examples/cancel_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.cancel(order_id="0xaaaa")
print(resp)
print("Done!")
main()
================================================
FILE: examples/cancel_orders.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.cancel_orders(["0xaaaa"])
print(resp)
print("Done!")
main()
================================================
FILE: examples/create_api_key.py
================================================
from dotenv import load_dotenv
import os
from py_clob_client.client import ClobClient
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id)
print(client.create_api_key())
main()
================================================
FILE: examples/create_readonly_api_key.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.create_readonly_api_key()
print(resp)
print("Done!")
main()
================================================
FILE: examples/delete_readonly_api_key.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Replace with the readonly API key you want to delete
readonly_api_key = "019aee85-4ea1-79cd-a287-8508f21209a2"
resp = client.delete_readonly_api_key(readonly_api_key)
print(resp)
print("Done!")
main()
================================================
FILE: examples/derive_api_key.py
================================================
from dotenv import load_dotenv
import os
from py_clob_client.client import ClobClient
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id)
print(client.derive_api_key())
main()
================================================
FILE: examples/drop_notifications.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, DropNotificationParams
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.drop_notifications(params=DropNotificationParams(ids=["1", "2"])))
main()
================================================
FILE: examples/get_api_keys.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.get_api_keys())
main()
================================================
FILE: examples/get_balance_allowance.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, BalanceAllowanceParams, AssetType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
collateral = client.get_balance_allowance(
params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL)
)
print(collateral)
yes = client.get_balance_allowance(
params=BalanceAllowanceParams(
asset_type=AssetType.CONDITIONAL,
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426",
)
)
print(yes)
no = client.get_balance_allowance(
params=BalanceAllowanceParams(
asset_type=AssetType.CONDITIONAL,
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
)
)
print(no)
main()
================================================
FILE: examples/get_builder_trades.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, TradeParams
from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds
from dotenv import load_dotenv
from pprint import pprint
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
builder_config = BuilderConfig(
local_builder_creds=BuilderApiKeyCreds(
key=os.getenv("BUILDER_API_KEY"),
secret=os.getenv("BUILDER_SECRET"),
passphrase=os.getenv("BUILDER_PASS_PHRASE"),
)
)
client = ClobClient(
host, key=key, chain_id=chain_id, creds=creds, builder_config=builder_config
)
resp = client.get_builder_trades()
pprint(resp)
print("Done!")
main()
================================================
FILE: examples/get_closed_only_mode.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.get_closed_only_mode())
main()
================================================
FILE: examples/get_last_trade_price.py
================================================
import os
from py_clob_client.client import ClobClient
from dotenv import load_dotenv
from pprint import pprint
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id)
resp = client.get_last_trade_price(
"71321045679252212594626385532706912750332728571942532289631379312455583992563"
)
pprint(resp)
print("Done!")
main()
================================================
FILE: examples/get_last_trades_prices.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
from dotenv import load_dotenv
from pprint import pprint
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id)
resp = client.get_last_trades_prices(
params=[
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563"
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426"
),
]
)
pprint(resp)
print("Done!")
main()
================================================
FILE: examples/get_market_trades_events.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.get_market_trades_events("condition_id"))
print("Done!")
main()
================================================
FILE: examples/get_markets.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.get_markets())
print(client.get_simplified_markets())
print(client.get_sampling_markets())
print(client.get_sampling_simplified_markets())
print(client.get_market("condition_id"))
print("Done!")
main()
================================================
FILE: examples/get_mid_market_price.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_midpoint(
"71321045679252212594626385532706912750332728571942532289631379312455583992563"
)
# {'mid': '0.55'}
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_mid_markets_prices.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, BookParams
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_midpoints(
params=[
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563"
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426"
),
]
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_notifications.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
print(client.get_notifications())
main()
================================================
FILE: examples/get_ok.py
================================================
from py_clob_client.client import ClobClient
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
print(client.get_ok())
pass
main()
================================================
FILE: examples/get_open_orders_with_readonly_key.py
================================================
import os
import httpx
from dotenv import load_dotenv
from py_clob_client.endpoints import ORDERS
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
# Replace with your address and readonly API key
address = os.getenv("POLY_ADDRESS", "0xc68576124eC1fF645F81a560E14003C8deF2e8fb")
readonly_api_key = os.getenv("CLOB_READONLY_API_KEY", "019aee85-4ea1-79cd-a287-8508f21209a2")
# Get all open orders for the address
response = httpx.get(
f"{host}{ORDERS}",
headers={
"POLY_READONLY_API_KEY": readonly_api_key,
"POLY_ADDRESS": address,
"Content-Type": "application/json",
},
params={
"maker_address": address,
},
follow_redirects=True,
)
if response.status_code == 200:
print(response.json())
else:
print(f"Error {response.status_code}: {response.text}")
print("Done!")
main()
================================================
FILE: examples/get_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_order(
"0xf5667d8509bdc78ac43676fe2c980da1365c471ee92153820c89c488fc15d539"
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_orderbook.py
================================================
from py_clob_client.client import ClobClient
import os
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
orderbook = client.get_order_book(
"34097058504275310827233323421517291090691602969494795225921954353603704046623"
)
print("orderbook", orderbook)
hash = client.get_order_book_hash(orderbook)
print("orderbook hash", hash)
main()
================================================
FILE: examples/get_orderbooks.py
================================================
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
resp = client.get_order_books(
params=[
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563"
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426"
),
]
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_orders.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OpenOrderParams
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_orders(
OpenOrderParams(
market="0x37a6a2dd9f3469495d9ec2467b0a764c5905371a294ce544bc3b2c944eb3e84a",
)
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_price.py
================================================
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
resp = client.get_price(
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
"BUY",
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_prices.py
================================================
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
resp = client.get_prices(
params=[
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
side="BUY",
),
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
side="SELL",
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426",
side="BUY",
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426",
side="SELL",
),
]
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_readonly_api_keys.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_readonly_api_keys()
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_server_time.py
================================================
from py_clob_client.client import ClobClient
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
print(client.get_server_time())
main()
================================================
FILE: examples/get_spread.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_spread(
"71321045679252212594626385532706912750332728571942532289631379312455583992563"
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_spreads.py
================================================
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import BookParams
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
client = ClobClient(host)
resp = client.get_spreads(
params=[
BookParams(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563"
),
BookParams(
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426"
),
]
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/get_trades.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, TradeParams
from dotenv import load_dotenv
from pprint import pprint
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.get_trades(
TradeParams(
maker_address=client.get_address(),
market="0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
)
)
pprint(resp)
print("Done!")
main()
================================================
FILE: examples/is_order_scoring.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderScoringParams
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
scoring = client.is_order_scoring(
OrderScoringParams(
orderId="0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc"
)
)
print(scoring)
print("Done!")
main()
================================================
FILE: examples/market_buy_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, MarketOrderArgs, OrderType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# create a market buy order for the equivalent of 100 USDC at the market price
order_args = MarketOrderArgs(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount=100, # $$$
side=BUY,
)
signed_order = client.create_market_order(order_args)
resp = client.post_order(signed_order, orderType=OrderType.FOK)
print(resp)
print("Done!")
main()
================================================
FILE: examples/market_sell_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, MarketOrderArgs, OrderType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import SELL
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# create a market buy order for the equivalent of 100 USDC at the market price
order_args = MarketOrderArgs(
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount=100, # SHARES
side=SELL,
)
signed_order = client.create_market_order(order_args)
resp = client.post_order(signed_order, orderType=OrderType.FOK)
print(resp)
print("Done!")
main()
================================================
FILE: examples/order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderArgs
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = int(os.getenv("CHAIN_ID", AMOY))
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Create and sign a limit order buying 100 YES tokens for 0.0005 each
order_args = OrderArgs(
price=0.0005,
size=20,
side=BUY,
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
)
signed_order = client.create_order(order_args)
resp = client.post_order(signed_order)
print(resp)
print("Done!")
main()
================================================
FILE: examples/orders.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderArgs, PostOrdersArgs, OrderType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY, SELL
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.post_orders(
[
PostOrdersArgs(
# Create and sign a limit order buying 100 YES tokens for 0.50 each
order=client.create_order(
OrderArgs(
price=0.5,
size=100,
side=BUY,
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
)
),
orderType=OrderType.GTC, # Good 'Til Cancelled
postOnly=False,
),
PostOrdersArgs(
# Create and sign a limit order selling 200 NO tokens for 0.25 each
order=client.create_order(
OrderArgs(
price=0.25,
size=200,
side=SELL,
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426",
)
),
orderType=OrderType.GTC, # Good 'Til Cancelled
postOnly=False, # Defaults to false, can be set to true to avoid matching on post
),
]
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/place_builder_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderArgs
from dotenv import load_dotenv
from py_clob_client.constants import POLYGON
from py_clob_client.order_builder.constants import BUY
from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = POLYGON
builder_config = BuilderConfig(
local_builder_creds=BuilderApiKeyCreds(
key=os.getenv("BUILDER_API_KEY"),
secret=os.getenv("BUILDER_SECRET"),
passphrase=os.getenv("BUILDER_PASS_PHRASE"),
)
)
client = ClobClient(
host, key=key, chain_id=chain_id, creds=creds, builder_config=builder_config
)
order_args = OrderArgs(
price=0.06,
size=20,
side=BUY,
token_id="104173557214744537570424345347209544585775842950109756851652855913015295701992",
)
signed_order = client.create_order(order_args)
resp = client.post_order(signed_order)
print(resp)
print("Done!")
main()
================================================
FILE: examples/post_heartbeat.py
================================================
import os
import time
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
heartbeat_id = None
while True:
resp = client.post_heartbeat(heartbeat_id)
print(resp)
heartbeat_id = resp["heartbeat_id"]
# Wait 5 seconds before sending the next heartbeat
time.sleep(5)
# Example output on invalid heartbeat ID once heartbeats started:
# PolyApiException[status_code=400, error_message={"error":"Invalid Heartbeat ID","heartbeat_id":"7f335bb3-36cb-433d-b8ff-4f9a2233d833"}
main()
================================================
FILE: examples/post_only_order.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, OrderArgs
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
from py_clob_client.clob_types import (OrderType)
from py_clob_client.order_builder.constants import BUY, SELL
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
order_args = OrderArgs(
price=0.4,
size=5,
side=BUY,
token_id="102200530570339469387764365697342150521708074903735836831685780223982723092914",
)
order = client.create_order(order_args)
resp = client.post_order(order, orderType=OrderType.GTC, post_only=True)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_accept_quote.py
================================================
import os
import time
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import AcceptQuoteParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Accept a quote (requester side)
# Refers to the order expiry, not request expiry. For request expiry, check the server RFQ config.
expiration = int(time.time()) + 3600
accept_params = AcceptQuoteParams(
request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601",
quote_id="019b04a7-5205-7eeb-9a48-227e8d53bd17",
expiration=expiration,
)
resp = client.rfq.accept_rfq_quote(accept_params)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_approve_order.py
================================================
import os
import time
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import ApproveOrderParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Approve an order (quoter side)
# Refers to the order expiry, not quote expiry. For quote expiry, check the server RFQ config.
expiration = int(time.time()) + 3600
approve_params = ApproveOrderParams(
request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601",
quote_id="019b04a7-5205-7eeb-9a48-227e8d53bd17",
expiration=expiration,
)
resp = client.rfq.approve_rfq_order(approve_params)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_cancel_quote.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import CancelRfqQuoteParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.rfq.cancel_rfq_quote(
CancelRfqQuoteParams(quote_id="0197656d-56ee-74a4-a06a-3b179121f3bf")
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_cancel_request.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import CancelRfqRequestParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.rfq.cancel_rfq_request(
CancelRfqRequestParams(request_id="0197656d-56ee-74a4-a06a-3b179121f3bf")
)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_config.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
resp = client.rfq.rfq_config()
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_create_quote.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import RfqUserQuote
from py_clob_client.order_builder.constants import SELL
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Create a quote for an RFQ request to SELL 40 tokens at $0.50 each
user_quote = RfqUserQuote(
request_id="019b04a4-2f4b-73b3-8fa2-2760b2754601",
token_id="34097058504275310827233323421517291090691602969494795225921954353603704046623",
price=0.50,
side=SELL,
size=40.0,
)
resp = client.rfq.create_rfq_quote(user_quote)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_create_request.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, PartialCreateOrderOptions
from py_clob_client.rfq import RfqUserRequest
from py_clob_client.order_builder.constants import BUY
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Create an RFQ request to BUY 100 tokens at $0.50 each
user_request = RfqUserRequest(
token_id="34097058504275310827233323421517291090691602969494795225921954353603704046623",
price=0.50,
side=BUY,
size=40.0,
)
resp = client.rfq.create_rfq_request(user_request, options=PartialCreateOrderOptions(tick_size=0.01))
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_full_flow.py
================================================
"""
RFQ Full Flow Example
This script demonstrates the complete RFQ (Request for Quote) flow between two parties.
For a single manual test, edit the REQUEST_PARAMS and QUOTE_PARAMS at the top.
This example assumes two EOA wallets.
For using different signature types, you need to set the funder address signature type when initializing the client.
Usage: python rfq_full_flow.py
TROUBLESHOOTING "invalid request" errors:
1. Ensure the tokenID exists in your environment (staging vs production)
2. Check that the market is active, RFQ-enabled and has liquidity
3. Verify your quoter has been whitelisted
4. Run `python examples/get_markets.py` to get valid token IDs
5. Make sure you're using the correct CLOB_API_URL for your environment
ENV VARIABLES:
REQUESTER_PK: Private key of the requester
REQUESTER_API_KEY: API key of the requester
REQUESTER_SECRET: Secret of the requester
REQUESTER_PASS_PHRASE: Passphrase of the requester
QUOTER_PK: Private key of the quoter
QUOTER_API_KEY: API key of the quoter
QUOTER_SECRET: Secret of the quoter
QUOTER_PASS_PHRASE: Passphrase of the quoter
CHAIN_ID: Chain ID of the network
CLOB_API_URL: URL of the CLOB API
"""
import os
import time
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import RfqUserRequest, RfqUserQuote, AcceptQuoteParams, ApproveOrderParams
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.constants import AMOY
load_dotenv()
# ============================================
# RFQ REQUEST PARAMETERS (REQUESTER) - EDIT THESE
# ============================================
TOKEN_ID = "34097058504275310827233323421517291090691602969494795225921954353603704046623"
USER_REQUEST = RfqUserRequest(
token_id=TOKEN_ID,
price=0.50, # Price per token (e.g., 0.50 = 50 cents)
side=BUY, # BUY or SELL
size=100.0, # Number of tokens
)
# ============================================
# RFQ QUOTE PARAMETERS (QUOTER) - EDIT THESE
# ============================================
QUOTE_TOKEN_ID = TOKEN_ID # Token ID for the quote (defaults to same as request)
QUOTE_PRICE = 0.50 # Quoted price per token
QUOTE_SIZE = 100.0 # Number of tokens to quote
QUOTE_SIDE = SELL # BUY or SELL
# ============================================
# EXPIRATION CONFIGURATION
# ============================================
EXPIRATION_SECONDS = 3600 # 1 hour
def main():
# ============================================
# Setup: Initialize both requester and quoter clients
# ============================================
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
# Requester (creates the request and accepts the quote)
requester_key = os.getenv("REQUESTER_PK")
requester_creds = ApiCreds(
api_key=os.getenv("REQUESTER_API_KEY"),
api_secret=os.getenv("REQUESTER_SECRET"),
api_passphrase=os.getenv("REQUESTER_PASS_PHRASE"),
)
requester_client = ClobClient(host, key=requester_key, chain_id=chain_id, creds=requester_creds)
# Quoter (creates the quote and approves the order)
quoter_key = os.getenv("QUOTER_PK")
quoter_creds = ApiCreds(
api_key=os.getenv("QUOTER_API_KEY"),
api_secret=os.getenv("QUOTER_SECRET"),
api_passphrase=os.getenv("QUOTER_PASS_PHRASE"),
)
quoter_client = ClobClient(host, key=quoter_key, chain_id=chain_id, creds=quoter_creds)
print("=" * 60)
print("RFQ Full Flow")
print("=" * 60)
print(f"Host: {host}")
print(f"Chain ID: {chain_id}")
print("=" * 60)
# ============================================
# Step 1: Requester creates RFQ request
# ============================================
print("\n[Step 1] Requester creating RFQ request...")
print(f" Token ID: {USER_REQUEST.token_id}")
print(f" Side: {USER_REQUEST.side}")
print(f" Size: {USER_REQUEST.size}")
print(f" Price: {USER_REQUEST.price}")
rfq_request_response = requester_client.rfq.create_rfq_request(USER_REQUEST)
# Check for errors
if rfq_request_response.get("error"):
print(f"Failed to create request. Error: {rfq_request_response['error']}")
raise Exception(f"Request creation failed: {rfq_request_response['error']}")
request_id = rfq_request_response.get("requestId")
if not request_id:
print(f"Failed to create request. Response: {rfq_request_response}")
raise Exception("Request creation failed - no requestId returned")
print("Request created successfully!")
print(f" Request ID: {request_id}")
print(f" Full response: {rfq_request_response}")
# ============================================
# Step 2: Quoter creates quote for the request
# ============================================
print("\n[Step 2] Quoter creating quote for request...")
print(f" Request ID: {request_id}")
print(f" Token ID: {QUOTE_TOKEN_ID}")
print(f" Price: {QUOTE_PRICE}")
print(f" Side: {QUOTE_SIDE}")
print(f" Size: {QUOTE_SIZE}")
user_quote = RfqUserQuote(
request_id=request_id,
token_id=QUOTE_TOKEN_ID,
price=QUOTE_PRICE,
side=QUOTE_SIDE,
size=QUOTE_SIZE,
)
rfq_quote_response = quoter_client.rfq.create_rfq_quote(user_quote)
# Check for errors
if rfq_quote_response.get("error"):
print(f"Failed to create quote. Error: {rfq_quote_response['error']}")
raise Exception(f"Quote creation failed: {rfq_quote_response['error']}")
quote_id = rfq_quote_response.get("quoteId")
if not quote_id:
print(f"Failed to create quote. Response: {rfq_quote_response}")
raise Exception("Quote creation failed - no quoteId returned")
print("Quote created successfully!")
print(f" Quote ID: {quote_id}")
print(f" Request ID: {request_id}")
print(f" Full response: {rfq_quote_response}")
# ============================================
# Step 3: Requester accepts the quote
# ============================================
print("\n[Step 3] Requester accepting quote...")
expiration = int(time.time()) + EXPIRATION_SECONDS
accept_params = AcceptQuoteParams(
request_id=request_id,
quote_id=quote_id,
expiration=expiration,
)
accept_result = requester_client.rfq.accept_rfq_quote(accept_params)
print(accept_result)
print("Quote accepted successfully!")
print(f" Request ID: {request_id}")
print(f" Quote ID: {quote_id}")
# ============================================
# Step 4: Quoter approves the order
# ============================================
print("\n[Step 4] Quoter approving order...")
approve_params = ApproveOrderParams(
request_id=request_id,
quote_id=quote_id,
expiration=expiration,
)
approve_result = quoter_client.rfq.approve_rfq_order(approve_params)
print(approve_result)
print("Order approved successfully!")
print(f" Request ID: {request_id}")
print(f" Quote ID: {quote_id}")
# ============================================
# Summary
# ============================================
print("\n" + "=" * 60)
print("RFQ FLOW COMPLETED SUCCESSFULLY!")
print("=" * 60)
print(f"Request ID: {request_id}")
print(f"Quote ID: {quote_id}")
print("=" * 60)
main()
================================================
FILE: examples/rfq_get_best_quote.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import GetRfqBestQuoteParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
params = GetRfqBestQuoteParams(
request_id=os.getenv("RFQ_REQUEST_ID", "019b9f8d-2336-70db-a0dd-071363fb1ff3")
)
resp = client.rfq.get_rfq_best_quote(params)
print(resp)
print("Done!")
main()
================================================
FILE: examples/rfq_get_quotes.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import GetRfqQuotesParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
params = GetRfqQuotesParams(
# quote_ids=["0197656d-56ee-74a4-a06a-3b179121f3bf"],
state="active",
# markets=["0x0000000000000000000000000000000000000000"],
# size_min=5,
# size_max=100,
# price_min=0.1,
# price_max=0.9,
# sort_by="price",
# sort_dir="asc",
limit=10,
# offset="MA==",
)
# Get quotes on your requests (requester view)
# Returns quotes that others have made on your RFQ requests
print("Requester quotes (quotes on my requests):")
requester_resp = client.rfq.get_rfq_requester_quotes(params)
print(requester_resp)
# Get quotes you've created (quoter view)
# Returns quotes that you have made on others' RFQ requests
print("\nQuoter quotes (quotes I've made):")
quoter_resp = client.rfq.get_rfq_quoter_quotes(params)
print(quoter_resp)
print("Done!")
main()
================================================
FILE: examples/rfq_get_requests.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_clob_client.rfq import GetRfqRequestsParams
from py_clob_client.constants import AMOY
from dotenv import load_dotenv
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob-staging.polymarket.com/")
chain_id = int(os.getenv("CHAIN_ID", AMOY))
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# Get all active RFQ requests
params = GetRfqRequestsParams(
# request_ids=["0197656d-56ee-74a4-a06a-3b179121f3bf"],
state="active",
# markets=["0x0000000000000000000000000000000000000000"],
# size_min=5,
# size_max=100,
# price_min=0.1,
# price_max=0.9,
# sort_by="price",
# sort_dir="asc",
limit=10,
offset="MA==",
)
resp = client.rfq.get_rfq_requests(params)
print(resp)
print("Done!")
main()
================================================
FILE: examples/update_balance_allowance.py
================================================
import os
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds, BalanceAllowanceParams, AssetType
from dotenv import load_dotenv
from py_clob_client.constants import AMOY
load_dotenv()
def main():
host = os.getenv("CLOB_API_URL", "https://clob.polymarket.com")
key = os.getenv("PK")
creds = ApiCreds(
api_key=os.getenv("CLOB_API_KEY"),
api_secret=os.getenv("CLOB_SECRET"),
api_passphrase=os.getenv("CLOB_PASS_PHRASE"),
)
chain_id = AMOY
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)
# USDC
client.update_balance_allowance(
params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL)
)
# YES
client.update_balance_allowance(
params=BalanceAllowanceParams(
asset_type=AssetType.CONDITIONAL,
token_id="52114319501245915516055106046884209969926127482827954674443846427813813222426",
)
)
# NO
client.update_balance_allowance(
params=BalanceAllowanceParams(
asset_type=AssetType.CONDITIONAL,
token_id="71321045679252212594626385532706912750332728571942532289631379312455583992563",
)
)
main()
================================================
FILE: py_clob_client/__init__.py
================================================
from .client import ClobClient
from .clob_types import (
ApiCreds,
OrderArgs,
MarketOrderArgs,
OrderType,
TickSize,
BookParams,
TradeParams,
OpenOrderParams,
BalanceAllowanceParams,
AssetType,
PartialCreateOrderOptions,
CreateOrderOptions,
)
# RFQ exports
from .rfq import (
RfqClient,
RfqUserRequest,
RfqUserQuote,
CreateRfqRequestParams,
CreateRfqQuoteParams,
CancelRfqRequestParams,
CancelRfqQuoteParams,
AcceptQuoteParams,
ApproveOrderParams,
GetRfqRequestsParams,
GetRfqQuotesParams,
GetRfqBestQuoteParams,
RfqRequest,
RfqQuote,
RfqRequestResponse,
RfqQuoteResponse,
RfqPaginatedResponse,
)
__all__ = [
# Main client
"ClobClient",
# Core types
"ApiCreds",
"OrderArgs",
"MarketOrderArgs",
"OrderType",
"TickSize",
"BookParams",
"TradeParams",
"OpenOrderParams",
"BalanceAllowanceParams",
"AssetType",
"PartialCreateOrderOptions",
"CreateOrderOptions",
# RFQ client
"RfqClient",
# RFQ input types
"RfqUserRequest",
"RfqUserQuote",
"CreateRfqRequestParams",
"CreateRfqQuoteParams",
"CancelRfqRequestParams",
"CancelRfqQuoteParams",
"AcceptQuoteParams",
"ApproveOrderParams",
"GetRfqRequestsParams",
"GetRfqQuotesParams",
"GetRfqBestQuoteParams",
# RFQ response types
"RfqRequest",
"RfqQuote",
"RfqRequestResponse",
"RfqQuoteResponse",
"RfqPaginatedResponse",
]
================================================
FILE: py_clob_client/client.py
================================================
import logging
import json
import time
from typing import Optional
from py_builder_signing_sdk.config import BuilderConfig
from .order_builder.builder import OrderBuilder
from .headers.headers import (
create_level_1_headers,
create_level_2_headers,
enrich_l2_headers_with_builder_headers,
)
from .signer import Signer
from .config import get_contract_config
from .endpoints import (
CANCEL,
CANCEL_ORDERS,
CANCEL_MARKET_ORDERS,
CANCEL_ALL,
CREATE_API_KEY,
DELETE_API_KEY,
DERIVE_API_KEY,
GET_API_KEYS,
CLOSED_ONLY,
CREATE_READONLY_API_KEY,
GET_READONLY_API_KEYS,
DELETE_READONLY_API_KEY,
VALIDATE_READONLY_API_KEY,
GET_LAST_TRADE_PRICE,
GET_ORDER,
GET_ORDER_BOOK,
MID_POINT,
ORDERS,
POST_ORDER,
POST_ORDERS,
PRICE,
TIME,
TRADES,
GET_NOTIFICATIONS,
DROP_NOTIFICATIONS,
GET_BALANCE_ALLOWANCE,
UPDATE_BALANCE_ALLOWANCE,
IS_ORDER_SCORING,
GET_TICK_SIZE,
GET_NEG_RISK,
GET_FEE_RATE,
ARE_ORDERS_SCORING,
GET_SIMPLIFIED_MARKETS,
GET_MARKETS,
GET_MARKET,
GET_SAMPLING_SIMPLIFIED_MARKETS,
GET_SAMPLING_MARKETS,
GET_MARKET_TRADES_EVENTS,
GET_LAST_TRADES_PRICES,
MID_POINTS,
GET_ORDER_BOOKS,
GET_PRICES,
GET_SPREAD,
GET_SPREADS,
GET_BUILDER_TRADES,
POST_HEARTBEAT,
)
from .clob_types import (
ApiCreds,
ReadonlyApiKeyResponse,
TradeParams,
OpenOrderParams,
OrderArgs,
RequestArgs,
DropNotificationParams,
OrderBookSummary,
BalanceAllowanceParams,
OrderScoringParams,
TickSize,
CreateOrderOptions,
OrdersScoringParams,
OrderType,
PartialCreateOrderOptions,
BookParams,
MarketOrderArgs,
PostOrdersArgs,
)
from .exceptions import PolyException
from .http_helpers.helpers import (
add_query_trade_params,
add_query_open_orders_params,
delete,
get,
post,
drop_notifications_query_params,
add_balance_allowance_params_to_url,
add_order_scoring_params_to_url,
)
from .constants import (
L0,
L1,
L1_AUTH_UNAVAILABLE,
L2,
L2_AUTH_UNAVAILABLE,
END_CURSOR,
BUILDER_AUTH_UNAVAILABLE,
)
from .utilities import (
parse_raw_orderbook_summary,
generate_orderbook_summary_hash,
order_to_json,
is_tick_size_smaller,
price_valid,
)
from .rfq import RfqClient
class ClobClient:
def __init__(
self,
host,
chain_id: int = None,
key: str = None,
creds: ApiCreds = None,
signature_type: int = None,
funder: str = None,
builder_config: BuilderConfig = None,
tick_size_ttl: float = 300.0,
):
"""
Initializes the clob client
The client can be started in 3 modes:
1) Level 0: Requires only the clob host url
Allows access to open CLOB endpoints
2) Level 1: Requires the host, chain_id and a private key.
Allows access to L1 authenticated endpoints + all unauthenticated endpoints
3) Level 2: Requires the host, chain_id, a private key, and Credentials.
Allows access to all endpoints
"""
self.host = host[0:-1] if host.endswith("/") else host
self.chain_id = chain_id
self.signer = Signer(key, chain_id) if key else None
self.creds = creds
self.mode = self._get_client_mode()
if self.signer:
self.builder = OrderBuilder(
self.signer, sig_type=signature_type, funder=funder
)
self.builder_config = None
if builder_config:
self.builder_config = builder_config
# local cache
self.__tick_sizes = {}
self.__tick_size_timestamps = {}
self.__tick_size_ttl = tick_size_ttl
self.__neg_risk = {}
self.__fee_rates = {}
# RFQ client
self.rfq = RfqClient(self)
self.logger = logging.getLogger(self.__class__.__name__)
def get_address(self):
"""
Returns the public address of the signer
"""
return self.signer.address() if self.signer else None
def get_collateral_address(self):
"""
Returns the collateral token address
"""
contract_config = get_contract_config(self.chain_id)
if contract_config:
return contract_config.collateral
def get_conditional_address(self):
"""
Returns the conditional token address
"""
contract_config = get_contract_config(self.chain_id)
if contract_config:
return contract_config.conditional_tokens
def get_exchange_address(self, neg_risk=False):
"""
Returns the exchange address
"""
contract_config = get_contract_config(self.chain_id, neg_risk)
if contract_config:
return contract_config.exchange
def get_ok(self):
"""
Health check: Confirms that the server is up
Does not need authentication
"""
return get("{}/".format(self.host))
def get_server_time(self):
"""
Returns the current timestamp on the server
Does not need authentication
"""
return get("{}{}".format(self.host, TIME))
def create_api_key(self, nonce: int = None) -> ApiCreds:
"""
Creates a new CLOB API key for the given
"""
self.assert_level_1_auth()
endpoint = "{}{}".format(self.host, CREATE_API_KEY)
headers = create_level_1_headers(self.signer, nonce)
creds_raw = post(endpoint, headers=headers)
try:
creds = ApiCreds(
api_key=creds_raw["apiKey"],
api_secret=creds_raw["secret"],
api_passphrase=creds_raw["passphrase"],
)
except:
self.logger.error("Couldn't parse created CLOB creds")
return None
return creds
def derive_api_key(self, nonce: int = None) -> ApiCreds:
"""
Derives an already existing CLOB API key for the given address and nonce
"""
self.assert_level_1_auth()
endpoint = "{}{}".format(self.host, DERIVE_API_KEY)
headers = create_level_1_headers(self.signer, nonce)
creds_raw = get(endpoint, headers=headers)
try:
creds = ApiCreds(
api_key=creds_raw["apiKey"],
api_secret=creds_raw["secret"],
api_passphrase=creds_raw["passphrase"],
)
except:
self.logger.error("Couldn't parse derived CLOB creds")
return None
return creds
def create_or_derive_api_creds(self, nonce: int = None) -> ApiCreds:
"""
Creates API creds if not already created for nonce, otherwise derives them
"""
try:
return self.create_api_key(nonce)
except:
return self.derive_api_key(nonce)
def set_api_creds(self, creds: ApiCreds):
"""
Sets client api creds
"""
self.creds = creds
self.mode = self._get_client_mode()
def get_api_keys(self):
"""
Gets the available API keys for this address
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=GET_API_KEYS)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return get("{}{}".format(self.host, GET_API_KEYS), headers=headers)
def get_closed_only_mode(self):
"""
Gets the closed only mode flag for thsi address
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=CLOSED_ONLY)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return get("{}{}".format(self.host, CLOSED_ONLY), headers=headers)
def delete_api_key(self):
"""
Deletes an API key
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="DELETE", request_path=DELETE_API_KEY)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete("{}{}".format(self.host, DELETE_API_KEY), headers=headers)
def create_readonly_api_key(self) -> ReadonlyApiKeyResponse:
"""
Creates a new readonly API key for a user
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="POST", request_path=CREATE_READONLY_API_KEY)
headers = create_level_2_headers(self.signer, self.creds, request_args)
response = post("{}{}".format(self.host, CREATE_READONLY_API_KEY), headers=headers)
try:
return ReadonlyApiKeyResponse(api_key=response["apiKey"])
except:
self.logger.error("Couldn't parse readonly API key response")
return None
def get_readonly_api_keys(self) -> list[str]:
"""
Gets the available readonly API keys for this address
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=GET_READONLY_API_KEYS)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return get("{}{}".format(self.host, GET_READONLY_API_KEYS), headers=headers)
def delete_readonly_api_key(self, key: str) -> bool:
"""
Deletes a readonly API key for a user
Level 2 Auth required
"""
self.assert_level_2_auth()
body = {"key": key}
serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
request_args = RequestArgs(
method="DELETE",
request_path=DELETE_READONLY_API_KEY,
body=body,
serialized_body=serialized,
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete(
"{}{}".format(self.host, DELETE_READONLY_API_KEY),
headers=headers,
data=serialized,
)
def validate_readonly_api_key(self, address: str, key: str) -> str:
"""
Validates a readonly API key for a given address
This is a public endpoint, no authentication required
"""
return get(
"{}{}?address={}&key={}".format(
self.host, VALIDATE_READONLY_API_KEY, address, key
)
)
def get_midpoint(self, token_id):
"""
Get the mid market price for the given market
"""
return get("{}{}?token_id={}".format(self.host, MID_POINT, token_id))
def get_midpoints(self, params: list[BookParams]):
"""
Get the mid market prices for a set of token ids
"""
body = [{"token_id": param.token_id} for param in params]
return post("{}{}".format(self.host, MID_POINTS), data=body)
def get_price(self, token_id, side):
"""
Get the market price for the given market
"""
return get("{}{}?token_id={}&side={}".format(self.host, PRICE, token_id, side))
def get_prices(self, params: list[BookParams]):
"""
Get the market prices for a set
"""
body = [{"token_id": param.token_id, "side": param.side} for param in params]
return post("{}{}".format(self.host, GET_PRICES), data=body)
def get_spread(self, token_id):
"""
Get the spread for the given market
"""
return get("{}{}?token_id={}".format(self.host, GET_SPREAD, token_id))
def get_spreads(self, params: list[BookParams]):
"""
Get the spreads for a set of token ids
"""
body = [{"token_id": param.token_id} for param in params]
return post("{}{}".format(self.host, GET_SPREADS), data=body)
def get_tick_size(self, token_id: str) -> TickSize:
cached_at = self.__tick_size_timestamps.get(token_id)
if (
token_id in self.__tick_sizes
and cached_at is not None
and (time.monotonic() - cached_at) < self.__tick_size_ttl
):
return self.__tick_sizes[token_id]
result = get("{}{}?token_id={}".format(self.host, GET_TICK_SIZE, token_id))
self.__tick_sizes[token_id] = str(result["minimum_tick_size"])
self.__tick_size_timestamps[token_id] = time.monotonic()
return self.__tick_sizes[token_id]
def clear_tick_size_cache(self, token_id: str = None):
"""
Clears the tick size cache, forcing fresh fetches on the next access.
Args:
token_id: If provided, only clears the cache for this token.
Otherwise clears all cached tick sizes.
"""
if token_id is not None:
self.__tick_sizes.pop(token_id, None)
self.__tick_size_timestamps.pop(token_id, None)
else:
self.__tick_sizes.clear()
self.__tick_size_timestamps.clear()
def _update_tick_size_from_order_book(self, book: OrderBookSummary):
"""
Opportunistically updates the tick size cache from an order book response.
"""
if book and book.asset_id and book.tick_size:
self.__tick_sizes[book.asset_id] = str(book.tick_size)
self.__tick_size_timestamps[book.asset_id] = time.monotonic()
def get_neg_risk(self, token_id: str) -> bool:
if token_id in self.__neg_risk:
return self.__neg_risk[token_id]
result = get("{}{}?token_id={}".format(self.host, GET_NEG_RISK, token_id))
self.__neg_risk[token_id] = result["neg_risk"]
return result["neg_risk"]
def get_fee_rate_bps(self, token_id: str) -> int:
if token_id in self.__fee_rates:
return self.__fee_rates[token_id]
result = get("{}{}?token_id={}".format(self.host, GET_FEE_RATE, token_id))
fee_rate = result.get("base_fee") or 0
self.__fee_rates[token_id] = fee_rate
return fee_rate
def __resolve_tick_size(
self, token_id: str, tick_size: TickSize = None
) -> TickSize:
min_tick_size = self.get_tick_size(token_id)
if tick_size is not None:
if is_tick_size_smaller(tick_size, min_tick_size):
raise Exception(
"invalid tick size ("
+ str(tick_size)
+ "), minimum for the market is "
+ str(min_tick_size),
)
else:
tick_size = min_tick_size
return tick_size
def __resolve_fee_rate(self, token_id: str, user_fee_rate: int = None) -> int:
market_fee_rate_bps = self.get_fee_rate_bps(token_id)
# If both fee rate on the market and the user supplied fee rate are non-zero, validate that they match
# else return the market fee rate
if (
market_fee_rate_bps is not None
and market_fee_rate_bps > 0
and user_fee_rate is not None
and user_fee_rate > 0
and user_fee_rate != market_fee_rate_bps
):
raise Exception(
f"invalid user provided fee rate: ({user_fee_rate}), fee rate for the market must be {market_fee_rate_bps}"
)
return market_fee_rate_bps
def create_order(
self, order_args: OrderArgs, options: Optional[PartialCreateOrderOptions] = None
):
"""
Creates and signs an order
Level 1 Auth required
"""
self.assert_level_1_auth()
# add resolve_order_options, or similar
tick_size = self.__resolve_tick_size(
order_args.token_id,
options.tick_size if options else None,
)
if not price_valid(order_args.price, tick_size):
raise Exception(
"price ("
+ str(order_args.price)
+ "), min: "
+ str(tick_size)
+ " - max: "
+ str(1 - float(tick_size))
)
neg_risk = (
options.neg_risk
if options and options.neg_risk
else self.get_neg_risk(order_args.token_id)
)
# fee rate
fee_rate_bps = self.__resolve_fee_rate(
order_args.token_id, order_args.fee_rate_bps
)
order_args.fee_rate_bps = fee_rate_bps
return self.builder.create_order(
order_args,
CreateOrderOptions(
tick_size=tick_size,
neg_risk=neg_risk,
),
)
def create_market_order(
self,
order_args: MarketOrderArgs,
options: Optional[PartialCreateOrderOptions] = None,
):
"""
Creates and signs an order
Level 1 Auth required
"""
self.assert_level_1_auth()
# add resolve_order_options, or similar
tick_size = self.__resolve_tick_size(
order_args.token_id,
options.tick_size if options else None,
)
if order_args.price is None or order_args.price <= 0:
order_args.price = self.calculate_market_price(
order_args.token_id,
order_args.side,
order_args.amount,
order_args.order_type,
)
if not price_valid(order_args.price, tick_size):
raise Exception(
"price ("
+ str(order_args.price)
+ "), min: "
+ str(tick_size)
+ " - max: "
+ str(1 - float(tick_size))
)
neg_risk = (
options.neg_risk
if options and options.neg_risk
else self.get_neg_risk(order_args.token_id)
)
# fee rate
fee_rate_bps = self.__resolve_fee_rate(
order_args.token_id, order_args.fee_rate_bps
)
order_args.fee_rate_bps = fee_rate_bps
return self.builder.create_market_order(
order_args,
CreateOrderOptions(
tick_size=tick_size,
neg_risk=neg_risk,
),
)
def post_orders(self, args: list[PostOrdersArgs]):
"""
Posts orders
"""
self.assert_level_2_auth()
body = [
order_to_json(arg.order, self.creds.api_key, arg.orderType, arg.postOnly) for arg in args
]
request_args = RequestArgs(
method="POST",
request_path=POST_ORDERS,
body=body,
serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False),
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
# Builder flow
if self.can_builder_auth():
builder_headers = self._generate_builder_headers(request_args, headers)
if builder_headers is not None:
return post(
"{}{}".format(self.host, POST_ORDERS),
headers=builder_headers,
data=request_args.serialized_body,
)
# send exact serialized bytes
return post(
"{}{}".format(self.host, POST_ORDERS),
headers=headers,
data=request_args.serialized_body,
)
def post_order(self, order, orderType: OrderType = OrderType.GTC, post_only: bool = False):
"""
Posts the order
"""
if post_only and (orderType != OrderType.GTC and orderType != OrderType.GTD):
raise Exception("post_only orders can only be of type GTC or GTD")
self.assert_level_2_auth()
body = order_to_json(order, self.creds.api_key, orderType, post_only)
request_args = RequestArgs(
method="POST",
request_path=POST_ORDER,
body=body,
serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False),
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
# Builder flow
if self.can_builder_auth():
builder_headers = self._generate_builder_headers(request_args, headers)
if builder_headers is not None:
return post(
"{}{}".format(self.host, POST_ORDER),
headers=builder_headers,
data=request_args.serialized_body,
)
return post(
"{}{}".format(self.host, POST_ORDER),
headers=headers,
data=request_args.serialized_body,
)
def create_and_post_order(
self, order_args: OrderArgs, options: PartialCreateOrderOptions = None
):
"""
Utility function to create and publish an order
"""
ord = self.create_order(order_args, options)
return self.post_order(ord)
def cancel(self, order_id):
"""
Cancels an order
Level 2 Auth required
"""
self.assert_level_2_auth()
body = {"orderID": order_id}
request_args = RequestArgs(
method="DELETE",
request_path=CANCEL,
body=body,
serialized_body=json.dumps(body, separators=(",", ":"), ensure_ascii=False),
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete(
"{}{}".format(self.host, CANCEL),
headers=headers,
data=request_args.serialized_body,
)
def cancel_orders(self, order_ids):
"""
Cancels orders
Level 2 Auth required
"""
self.assert_level_2_auth()
body = order_ids
serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
request_args = RequestArgs(
method="DELETE",
request_path=CANCEL_ORDERS,
body=body,
serialized_body=serialized,
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete(
"{}{}".format(self.host, CANCEL_ORDERS), headers=headers, data=serialized
)
def cancel_all(self):
"""
Cancels all available orders for the user
Level 2 Auth required
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="DELETE", request_path=CANCEL_ALL)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete("{}{}".format(self.host, CANCEL_ALL), headers=headers)
def post_heartbeat(self, heartbeat_id: Optional[str]):
"""
Sends a heartbeat to the server, if heartbeats are started and one isn't sent within 10s, all orders will be cancelled
Requires Level 2 authentication
"""
self.assert_level_2_auth()
body = {"heartbeat_id": heartbeat_id}
serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
request_args = RequestArgs(method="POST", request_path=POST_HEARTBEAT, body=body, serialized_body=serialized)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return post(
"{}{}".format(self.host, POST_HEARTBEAT),
headers=headers,
data=serialized
)
def cancel_market_orders(self, market: str = "", asset_id: str = ""):
"""
Cancels orders
Level 2 Auth required
"""
self.assert_level_2_auth()
body = {"market": market, "asset_id": asset_id}
serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
request_args = RequestArgs(
method="DELETE",
request_path=CANCEL_MARKET_ORDERS,
body=body,
serialized_body=serialized,
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return delete(
"{}{}".format(self.host, CANCEL_MARKET_ORDERS),
headers=headers,
data=serialized,
)
def get_orders(self, params: OpenOrderParams = None, next_cursor="MA=="):
"""
Gets orders for the API key
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=ORDERS)
headers = create_level_2_headers(self.signer, self.creds, request_args)
results = []
next_cursor = next_cursor if next_cursor is not None else "MA=="
while next_cursor != END_CURSOR:
url = add_query_open_orders_params(
"{}{}".format(self.host, ORDERS), params, next_cursor
)
response = get(url, headers=headers)
next_cursor = response["next_cursor"]
results += response["data"]
return results
def get_order_book(self, token_id) -> OrderBookSummary:
"""
Fetches the orderbook for the token_id
"""
raw_obs = get("{}{}?token_id={}".format(self.host, GET_ORDER_BOOK, token_id))
result = parse_raw_orderbook_summary(raw_obs)
self._update_tick_size_from_order_book(result)
return result
def get_order_books(self, params: list[BookParams]) -> list[OrderBookSummary]:
"""
Fetches the orderbook for a set of token ids
"""
body = [{"token_id": param.token_id} for param in params]
raw_obs = post("{}{}".format(self.host, GET_ORDER_BOOKS), data=body)
results = [parse_raw_orderbook_summary(r) for r in raw_obs]
for book in results:
self._update_tick_size_from_order_book(book)
return results
def get_order_book_hash(self, orderbook: OrderBookSummary) -> str:
"""
Calculates the hash for the given orderbook
"""
return generate_orderbook_summary_hash(orderbook)
def get_order(self, order_id):
"""
Fetches the order corresponding to the order_id
Requires Level 2 authentication
"""
self.assert_level_2_auth()
endpoint = "{}{}".format(GET_ORDER, order_id)
request_args = RequestArgs(method="GET", request_path=endpoint)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return get("{}{}".format(self.host, endpoint), headers=headers)
def get_trades(self, params: TradeParams = None, next_cursor="MA=="):
"""
Fetches the trade history for a user
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=TRADES)
headers = create_level_2_headers(self.signer, self.creds, request_args)
results = []
next_cursor = next_cursor if next_cursor is not None else "MA=="
while next_cursor != END_CURSOR:
url = add_query_trade_params(
"{}{}".format(self.host, TRADES), params, next_cursor
)
response = get(url, headers=headers)
next_cursor = response["next_cursor"]
results += response["data"]
return results
def get_last_trade_price(self, token_id):
"""
Fetches the last trade price token_id
"""
return get("{}{}?token_id={}".format(self.host, GET_LAST_TRADE_PRICE, token_id))
def get_last_trades_prices(self, params: list[BookParams]):
"""
Fetches the last trades prices for a set of token ids
"""
body = [{"token_id": param.token_id} for param in params]
return post("{}{}".format(self.host, GET_LAST_TRADES_PRICES), data=body)
def assert_level_1_auth(self):
"""
Level 1 Poly Auth
"""
if self.mode < L1:
raise PolyException(L1_AUTH_UNAVAILABLE)
def assert_level_2_auth(self):
"""
Level 2 Poly Auth
"""
if self.mode < L2:
raise PolyException(L2_AUTH_UNAVAILABLE)
def assert_builder_auth(self):
"""
Builder Auth
"""
if not self.can_builder_auth():
raise PolyException(BUILDER_AUTH_UNAVAILABLE)
def can_builder_auth(self) -> bool:
return self.builder_config is not None and self.builder_config.is_valid()
def _get_client_mode(self):
if self.signer is not None and self.creds is not None:
return L2
if self.signer is not None:
return L1
return L0
def _generate_builder_headers(self, request_args: RequestArgs, headers: dict):
"""
Generates builder headers and attaches them to the L2 Header
"""
if self.builder_config is not None:
builder_headers = self._get_builder_headers(
request_args.method,
request_args.request_path,
request_args.serialized_body,
)
if builder_headers is None:
return None
return enrich_l2_headers_with_builder_headers(headers, builder_headers)
return None
def _get_builder_headers(self, method: str, path: str, body: Optional[str] = None):
"""
Generates builder headers for the given method, path, and body.
Args:
method (str): HTTP method.
path (str): Request path.
body (Optional[str]): Pre-serialized JSON string or None.
Returns:
dict or None: Builder headers as a dictionary, or None if not available.
"""
headers = self.builder_config.generate_builder_headers(method, path, body)
if headers:
return headers.to_dict()
return None
def get_notifications(self):
"""
Fetches the notifications for a user
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=GET_NOTIFICATIONS)
headers = create_level_2_headers(self.signer, self.creds, request_args)
url = "{}{}?signature_type={}".format(
self.host, GET_NOTIFICATIONS, self.builder.sig_type
)
return get(url, headers=headers)
def drop_notifications(self, params: DropNotificationParams = None):
"""
Drops the notifications for a user
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="DELETE", request_path=DROP_NOTIFICATIONS)
headers = create_level_2_headers(self.signer, self.creds, request_args)
url = drop_notifications_query_params(
"{}{}".format(self.host, DROP_NOTIFICATIONS), params
)
return delete(url, headers=headers)
def get_balance_allowance(self, params: BalanceAllowanceParams = None):
"""
Fetches the balance & allowance for a user
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=GET_BALANCE_ALLOWANCE)
headers = create_level_2_headers(self.signer, self.creds, request_args)
if params.signature_type == -1:
params.signature_type = self.builder.sig_type
url = add_balance_allowance_params_to_url(
"{}{}".format(self.host, GET_BALANCE_ALLOWANCE), params
)
return get(url, headers=headers)
def update_balance_allowance(self, params: BalanceAllowanceParams = None):
"""
Updates the balance & allowance for a user
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=UPDATE_BALANCE_ALLOWANCE)
headers = create_level_2_headers(self.signer, self.creds, request_args)
if params.signature_type == -1:
params.signature_type = self.builder.sig_type
url = add_balance_allowance_params_to_url(
"{}{}".format(self.host, UPDATE_BALANCE_ALLOWANCE), params
)
return get(url, headers=headers)
def is_order_scoring(self, params: OrderScoringParams):
"""
Check if the order is currently scoring
Requires Level 2 authentication
"""
self.assert_level_2_auth()
request_args = RequestArgs(method="GET", request_path=IS_ORDER_SCORING)
headers = create_level_2_headers(self.signer, self.creds, request_args)
url = add_order_scoring_params_to_url(
"{}{}".format(self.host, IS_ORDER_SCORING), params
)
return get(url, headers=headers)
def are_orders_scoring(self, params: OrdersScoringParams):
"""
Check if the orders are currently scoring
Requires Level 2 authentication
"""
self.assert_level_2_auth()
body = params.orderIds
serialized = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
request_args = RequestArgs(
method="POST",
request_path=ARE_ORDERS_SCORING,
body=body,
serialized_body=serialized,
)
headers = create_level_2_headers(self.signer, self.creds, request_args)
return post(
"{}{}".format(self.host, ARE_ORDERS_SCORING),
headers=headers,
data=serialized,
)
def get_sampling_markets(self, next_cursor="MA=="):
"""
Get the current sampling markets
"""
return get(
"{}{}?next_cursor={}".format(self.host, GET_SAMPLING_MARKETS, next_cursor)
)
def get_sampling_simplified_markets(self, next_cursor="MA=="):
"""
Get the current sampling simplified markets
"""
return get(
"{}{}?next_cursor={}".format(
self.host, GET_SAMPLING_SIMPLIFIED_MARKETS, next_cursor
)
)
def get_markets(self, next_cursor="MA=="):
"""
Get the current markets
"""
return get("{}{}?next_cursor={}".format(self.host, GET_MARKETS, next_cursor))
def get_simplified_markets(self, next_cursor="MA=="):
"""
Get the current simplified markets
"""
return get(
"{}{}?next_cursor={}".format(self.host, GET_SIMPLIFIED_MARKETS, next_cursor)
)
def get_market(self, condition_id):
"""
Get a market by condition_id
"""
return get("{}{}{}".format(self.host, GET_MARKET, condition_id))
def get_market_trades_events(self, condition_id):
"""
Get the market's trades events by condition id
"""
return get("{}{}{}".format(self.host, GET_MARKET_TRADES_EVENTS, condition_id))
def get_builder_trades(self, params: TradeParams = None, next_cursor="MA=="):
"""
Get trades originated by the builder
"""
self.assert_builder_auth()
request_args = RequestArgs(method="GET", request_path=GET_BUILDER_TRADES)
headers = self._get_builder_headers(
request_args.method, request_args.request_path, request_args.body
)
results = []
next_cursor = next_cursor if next_cursor is not None else "MA=="
while next_cursor != END_CURSOR:
url = add_query_trade_params(
"{}{}".format(self.host, GET_BUILDER_TRADES), params, next_cursor
)
response = get(url, headers=headers)
next_cursor = response["next_cursor"]
results += response["data"]
return results
def calculate_market_price(
self, token_id: str, side: str, amount: float, order_type: OrderType
) -> float:
"""
Calculates the matching price considering an amount and the current orderbook
"""
book = self.get_order_book(token_id)
if book is None:
raise Exception("no orderbook")
if side == "BUY":
if book.asks is None:
raise Exception("no match")
return self.builder.calculate_buy_market_price(
book.asks, amount, order_type
)
else:
if book.bids is None:
raise Exception("no match")
return self.builder.calculate_sell_market_price(
book.bids, amount, order_type
)
================================================
FILE: py_clob_client/clob_types.py
================================================
from typing import Any
from dataclasses import dataclass, asdict
from json import dumps
from typing import Literal, Optional
from py_order_utils.model import (
SignedOrder,
)
from .constants import ZERO_ADDRESS
class OrderType(enumerate):
GTC = "GTC"
FOK = "FOK"
GTD = "GTD"
FAK = "FAK"
@dataclass
class ApiCreds:
api_key: str
api_secret: str
api_passphrase: str
@dataclass
class ReadonlyApiKeyResponse:
api_key: str
@dataclass
class RequestArgs:
method: str
request_path: str
body: Any = None
serialized_body: Optional[str] = None
@dataclass
class BookParams:
token_id: str
side: str = ""
@dataclass
class OrderArgs:
token_id: str
"""
TokenID of the Conditional token asset being traded
"""
price: float
"""
Price used to create the order
"""
size: float
"""
Size in terms of the ConditionalToken
"""
side: str
"""
Side of the order
"""
fee_rate_bps: int = 0
"""
Fee rate, in basis points, charged to the order maker, charged on proceeds
"""
nonce: int = 0
"""
Nonce used for onchain cancellations
"""
expiration: int = 0
"""
Timestamp after which the order is expired.
"""
taker: str = ZERO_ADDRESS
"""
Address of the order taker. The zero address is used to indicate a public order
"""
@dataclass
class MarketOrderArgs:
token_id: str
"""
TokenID of the Conditional token asset being traded
"""
amount: float
"""
BUY orders: $$$ Amount to buy
SELL orders: Shares to sell
"""
side: str
"""
Side of the order
"""
price: float = 0
"""
Price used to create the order
"""
fee_rate_bps: int = 0
"""
Fee rate, in basis points, charged to the order maker, charged on proceeds
"""
nonce: int = 0
"""
Nonce used for onchain cancellations
"""
taker: str = ZERO_ADDRESS
"""
Address of the order taker. The zero address is used to indicate a public order
"""
order_type: OrderType = OrderType.FOK
@dataclass
class TradeParams:
id: str = None
maker_address: str = None
market: str = None
asset_id: str = None
before: int = None
after: int = None
@dataclass
class OpenOrderParams:
id: str = None
market: str = None
asset_id: str = None
@dataclass
class DropNotificationParams:
ids: list[str] = None
@dataclass
class OrderSummary:
price: str = None
size: str = None
@property
def __dict__(self):
return asdict(self)
@property
def json(self):
return dumps(self.__dict__)
@dataclass
class OrderBookSummary:
market: str = None
asset_id: str = None
timestamp: str = None
bids: list[OrderSummary] = None
asks: list[OrderSummary] = None
min_order_size: str = None
neg_risk: bool = None
tick_size: str = None
last_trade_price: str = None
hash: str = None
@property
def __dict__(self):
return asdict(self)
@property
def json(self):
return dumps(self.__dict__, separators=(",", ":"))
class AssetType(enumerate):
COLLATERAL = "COLLATERAL"
CONDITIONAL = "CONDITIONAL"
@dataclass
class BalanceAllowanceParams:
asset_type: AssetType = None
token_id: str = None
signature_type: int = -1
@dataclass
class OrderScoringParams:
orderId: str
@dataclass
class OrdersScoringParams:
orderIds: list[str]
TickSize = Literal["0.1", "0.01", "0.001", "0.0001"]
@dataclass
class CreateOrderOptions:
tick_size: TickSize
neg_risk: bool
@dataclass
class PartialCreateOrderOptions:
tick_size: Optional[TickSize] = None
neg_risk: Optional[bool] = None
@dataclass
class RoundConfig:
price: float
size: float
amount: float
@dataclass
class ContractConfig:
"""
Contract Configuration
"""
exchange: str
"""
The exchange contract responsible for matching orders
"""
collateral: str
"""
The ERC20 token used as collateral for the exchange's markets
"""
conditional_tokens: str
"""
The ERC1155 conditional tokens contract
"""
@dataclass
class PostOrdersArgs:
order: SignedOrder
orderType: OrderType = OrderType.GTC
postOnly: bool = False
================================================
FILE: py_clob_client/config.py
================================================
from .clob_types import ContractConfig
def get_contract_config(chainID: int, neg_risk: bool = False) -> ContractConfig:
"""
Get the contract configuration for the chain
"""
CONFIG = {
137: ContractConfig(
exchange="0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
collateral="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
conditional_tokens="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
),
80002: ContractConfig(
exchange="0xdFE02Eb6733538f8Ea35D585af8DE5958AD99E40",
collateral="0x9c4e1703476e875070ee25b56a58b008cfb8fa78",
conditional_tokens="0x69308FB512518e39F9b16112fA8d994F4e2Bf8bB",
),
}
NEG_RISK_CONFIG = {
137: ContractConfig(
exchange="0xC5d563A36AE78145C45a50134d48A1215220f80a",
collateral="0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
conditional_tokens="0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
),
80002: ContractConfig(
exchange="0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296",
collateral="0x9c4e1703476e875070ee25b56a58b008cfb8fa78",
conditional_tokens="0x69308FB512518e39F9b16112fA8d994F4e2Bf8bB",
),
}
if neg_risk:
config = NEG_RISK_CONFIG.get(chainID)
else:
config = CONFIG.get(chainID)
if config is None:
raise Exception("Invalid chainID: ${}".format(chainID))
return config
================================================
FILE: py_clob_client/constants.py
================================================
# Access levels
L0 = 0
L1 = 1
L2 = 2
CREDENTIAL_CREATION_WARNING = """🚨🚨🚨
Your credentials CANNOT be recovered after they've been created.
Be sure to store them safely!
🚨🚨🚨"""
L1_AUTH_UNAVAILABLE = "A private key is needed to interact with this endpoint!"
L2_AUTH_UNAVAILABLE = "API Credentials are needed to interact with this endpoint!"
BUILDER_AUTH_UNAVAILABLE = (
"Builder API Credentials needed to interact with this endpoint!"
)
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
AMOY = 80002
POLYGON = 137
END_CURSOR = "LTE="
================================================
FILE: py_clob_client/endpoints.py
================================================
TIME = "/time"
CREATE_API_KEY = "/auth/api-key"
GET_API_KEYS = "/auth/api-keys"
DELETE_API_KEY = "/auth/api-key"
DERIVE_API_KEY = "/auth/derive-api-key"
CLOSED_ONLY = "/auth/ban-status/closed-only"
# Readonly API Key endpoints
CREATE_READONLY_API_KEY = "/auth/readonly-api-key"
GET_READONLY_API_KEYS = "/auth/readonly-api-keys"
DELETE_READONLY_API_KEY = "/auth/readonly-api-key"
VALIDATE_READONLY_API_KEY = "/auth/validate-readonly-api-key"
TRADES = "/data/trades"
GET_ORDER_BOOK = "/book"
GET_ORDER_BOOKS = "/books"
GET_ORDER = "/data/order/"
ORDERS = "/data/orders"
POST_ORDER = "/order"
POST_ORDERS = "/orders"
CANCEL = "/order"
CANCEL_ORDERS = "/orders"
CANCEL_ALL = "/cancel-all"
CANCEL_MARKET_ORDERS = "/cancel-market-orders"
MID_POINT = "/midpoint"
MID_POINTS = "/midpoints"
PRICE = "/price"
GET_PRICES = "/prices"
GET_SPREAD = "/spread"
GET_SPREADS = "/spreads"
GET_LAST_TRADE_PRICE = "/last-trade-price"
GET_LAST_TRADES_PRICES = "/last-trades-prices"
GET_NOTIFICATIONS = "/notifications"
DROP_NOTIFICATIONS = "/notifications"
GET_BALANCE_ALLOWANCE = "/balance-allowance"
UPDATE_BALANCE_ALLOWANCE = "/balance-allowance/update"
IS_ORDER_SCORING = "/order-scoring"
ARE_ORDERS_SCORING = "/orders-scoring"
GET_TICK_SIZE = "/tick-size"
GET_NEG_RISK = "/neg-risk"
GET_FEE_RATE = "/fee-rate"
GET_SAMPLING_SIMPLIFIED_MARKETS = "/sampling-simplified-markets"
GET_SAMPLING_MARKETS = "/sampling-markets"
GET_SIMPLIFIED_MARKETS = "/simplified-markets"
GET_MARKETS = "/markets"
GET_MARKET = "/markets/"
GET_MARKET_TRADES_EVENTS = "/live-activity/events/"
POST_HEARTBEAT = "/v1/heartbeats"
GET_BUILDER_TRADES = "/builder/trades"
# RFQ Endpoints
CREATE_RFQ_REQUEST = "/rfq/request"
CANCEL_RFQ_REQUEST = "/rfq/request"
GET_RFQ_REQUESTS = "/rfq/data/requests"
CREATE_RFQ_QUOTE = "/rfq/quote"
CANCEL_RFQ_QUOTE = "/rfq/quote"
GET_RFQ_REQUESTER_QUOTES = "/rfq/data/requester/quotes"
GET_RFQ_QUOTER_QUOTES = "/rfq/data/quoter/quotes"
GET_RFQ_BEST_QUOTE = "/rfq/data/best-quote"
RFQ_REQUESTS_ACCEPT = "/rfq/request/accept"
RFQ_QUOTE_APPROVE = "/rfq/quote/approve"
RFQ_CONFIG = "/rfq/config"
================================================
FILE: py_clob_client/exceptions.py
================================================
from typing import Optional
import httpx
class PolyException(Exception):
def __init__(self, msg):
self.msg = msg
class PolyApiException(PolyException):
def __init__(self, resp: Optional[httpx.Response] = None, error_msg=None):
assert resp is not None or error_msg is not None
if resp is not None:
self.status_code = resp.status_code
self.error_msg = self._get_message(resp)
else:
self.status_code = None
self.error_msg = error_msg
def _get_message(self, resp: httpx.Response):
try:
return resp.json()
except Exception:
return resp.text
def __repr__(self):
return f"PolyApiException[status_code={self.status_code}, error_message={self.error_msg}]"
def __str__(self):
return self.__repr__()
================================================
FILE: py_clob_client/headers/__init__.py
================================================
================================================
FILE: py_clob_client/headers/headers.py
================================================
from ..clob_types import ApiCreds, RequestArgs
from ..signing.hmac import build_hmac_signature
from ..signer import Signer
from ..signing.eip712 import sign_clob_auth_message
from datetime import datetime
POLY_ADDRESS = "POLY_ADDRESS"
POLY_SIGNATURE = "POLY_SIGNATURE"
POLY_TIMESTAMP = "POLY_TIMESTAMP"
POLY_NONCE = "POLY_NONCE"
POLY_API_KEY = "POLY_API_KEY"
POLY_PASSPHRASE = "POLY_PASSPHRASE"
def create_level_1_headers(signer: Signer, nonce: int = None):
"""
Creates Level 1 Poly headers for a request
"""
timestamp = int(datetime.now().timestamp())
n = 0
if nonce is not None:
n = nonce
signature = sign_clob_auth_message(signer, timestamp, n)
headers = {
POLY_ADDRESS: signer.address(),
POLY_SIGNATURE: signature,
POLY_TIMESTAMP: str(timestamp),
POLY_NONCE: str(n),
}
return headers
def create_level_2_headers(signer: Signer, creds: ApiCreds, request_args: RequestArgs):
"""Creates Level 2 Poly headers for a request using pre-serialized body if provided"""
timestamp = int(datetime.now().timestamp())
# Prefer the pre-serialized body string for deterministic signing if available
body_for_sig = (
request_args.serialized_body
if request_args.serialized_body is not None
else request_args.body
)
hmac_sig = build_hmac_signature(
creds.api_secret,
timestamp,
request_args.method,
request_args.request_path,
body_for_sig,
)
return {
POLY_ADDRESS: signer.address(),
POLY_SIGNATURE: hmac_sig,
POLY_TIMESTAMP: str(timestamp),
POLY_API_KEY: creds.api_key,
POLY_PASSPHRASE: creds.api_passphrase,
}
def enrich_l2_headers_with_builder_headers(
headers: dict, builder_headers: dict
) -> dict:
return {**headers, **builder_headers}
================================================
FILE: py_clob_client/http_helpers/__init__.py
================================================
================================================
FILE: py_clob_client/http_helpers/helpers.py
================================================
import httpx
from py_clob_client.clob_types import (
DropNotificationParams,
BalanceAllowanceParams,
OrderScoringParams,
OrdersScoringParams,
TradeParams,
OpenOrderParams,
)
from ..exceptions import PolyApiException
GET = "GET"
POST = "POST"
DELETE = "DELETE"
PUT = "PUT"
_http_client = httpx.Client(http2=True)
def overloadHeaders(method: str, headers: dict) -> dict:
if headers is None:
headers = dict()
headers["User-Agent"] = "py_clob_client"
headers["Accept"] = "*/*"
headers["Connection"] = "keep-alive"
headers["Content-Type"] = "application/json"
if method == GET:
headers["Accept-Encoding"] = "gzip"
return headers
def request(endpoint: str, method: str, headers=None, data=None):
try:
headers = overloadHeaders(method, headers)
if isinstance(data, str):
# Pre-serialized body: send exact bytes
resp = _http_client.request(
method=method,
url=endpoint,
headers=headers,
content=data.encode("utf-8"),
)
else:
resp = _http_client.request(
method=method,
url=endpoint,
headers=headers,
json=data,
)
if resp.status_code != 200:
raise PolyApiException(resp)
try:
return resp.json()
except ValueError:
return resp.text
except httpx.RequestError:
raise PolyApiException(error_msg="Request exception!")
def post(endpoint, headers=None, data=None):
return request(endpoint, POST, headers, data)
def get(endpoint, headers=None, data=None):
return request(endpoint, GET, headers, data)
def delete(endpoint, headers=None, data=None):
return request(endpoint, DELETE, headers, data)
def put(endpoint, headers=None, data=None):
return request(endpoint, PUT, headers, data)
def build_query_params(url: str, param: str, val: str) -> str:
url_with_params = url
last = url_with_params[-1]
# if last character in url string == "?", append the param directly: api.com?param=value
if last == "?":
url_with_params = "{}{}={}".format(url_with_params, param, val)
else:
# else add "&", then append the param
url_with_params = "{}&{}={}".format(url_with_params, param, val)
return url_with_params
def add_query_trade_params(
base_url: str, params: TradeParams = None, next_cursor="MA=="
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
# Include `next_cursor` even when `params` is None to advance pagination.
has_query = bool(next_cursor) or (
bool(params)
and any(
[
params.market,
params.asset_id,
params.after,
params.before,
params.maker_address,
params.id,
]
)
)
if has_query:
url = url + "?"
if params:
if params.market:
url = build_query_params(url, "market", params.market)
if params.asset_id:
url = build_query_params(url, "asset_id", params.asset_id)
if params.after:
url = build_query_params(url, "after", params.after)
if params.before:
url = build_query_params(url, "before", params.before)
if params.maker_address:
url = build_query_params(url, "maker_address", params.maker_address)
if params.id:
url = build_query_params(url, "id", params.id)
if next_cursor:
url = build_query_params(url, "next_cursor", next_cursor)
return url
def add_query_open_orders_params(
base_url: str, params: OpenOrderParams = None, next_cursor="MA=="
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
# Include `next_cursor` even when `params` is None to advance pagination.
has_query = bool(next_cursor) or (
bool(params) and any([params.market, params.asset_id, params.id])
)
if has_query:
url = url + "?"
if params:
if params.market:
url = build_query_params(url, "market", params.market)
if params.asset_id:
url = build_query_params(url, "asset_id", params.asset_id)
if params.id:
url = build_query_params(url, "id", params.id)
if next_cursor:
url = build_query_params(url, "next_cursor", next_cursor)
return url
def drop_notifications_query_params(
base_url: str, params: DropNotificationParams = None
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
if params:
url = url + "?"
if params.ids:
url = build_query_params(url, "ids", ",".join(params.ids))
return url
def add_balance_allowance_params_to_url(
base_url: str, params: BalanceAllowanceParams = None
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
if params:
url = url + "?"
if params.asset_type:
url = build_query_params(url, "asset_type", params.asset_type.__str__())
if params.token_id:
url = build_query_params(url, "token_id", params.token_id)
if params.signature_type is not None:
url = build_query_params(url, "signature_type", params.signature_type)
return url
def add_order_scoring_params_to_url(
base_url: str, params: OrderScoringParams = None
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
if params:
url = url + "?"
if params.orderId:
url = build_query_params(url, "order_id", params.orderId)
return url
def add_orders_scoring_params_to_url(
base_url: str, params: OrdersScoringParams = None
) -> str:
"""
Adds query parameters to a url
"""
url = base_url
if params:
url = url + "?"
if params.orderIds:
url = build_query_params(url, "order_ids", ",".join(params.orderIds))
return url
================================================
FILE: py_clob_client/order_builder/__init__.py
================================================
================================================
FILE: py_clob_client/order_builder/builder.py
================================================
from py_order_utils.builders import OrderBuilder as UtilsOrderBuilder
from py_order_utils.signer import Signer as UtilsSigner
from py_order_utils.model import (
EOA,
OrderData,
SignedOrder,
BUY as UtilsBuy,
SELL as UtilsSell,
)
from .helpers import (
to_token_decimals,
round_down,
round_normal,
decimal_places,
round_up,
)
from .constants import BUY, SELL
from ..config import get_contract_config
from ..signer import Signer
from ..clob_types import (
OrderArgs,
CreateOrderOptions,
TickSize,
RoundConfig,
MarketOrderArgs,
OrderSummary,
OrderType,
)
ROUNDING_CONFIG: dict[TickSize, RoundConfig] = {
"0.1": RoundConfig(price=1, size=2, amount=3),
"0.01": RoundConfig(price=2, size=2, amount=4),
"0.001": RoundConfig(price=3, size=2, amount=5),
"0.0001": RoundConfig(price=4, size=2, amount=6),
}
class OrderBuilder:
def __init__(self, signer: Signer, sig_type=None, funder=None):
self.signer = signer
# Signature type used sign orders, defaults to EOA type
self.sig_type = sig_type if sig_type is not None else EOA
# Address which holds funds to be used.
# Used for Polymarket proxy wallets and other smart contract wallets
# Defaults to the address of the signer
self.funder = funder if funder is not None else self.signer.address()
def get_order_amounts(
self, side: str, size: float, price: float, round_config: RoundConfig
):
raw_price = round_normal(price, round_config.price)
if side == BUY:
raw_taker_amt = round_down(size, round_config.size)
raw_maker_amt = raw_taker_amt * raw_price
if decimal_places(raw_maker_amt) > round_config.amount:
raw_maker_amt = round_up(raw_maker_amt, round_config.amount + 4)
if decimal_places(raw_maker_amt) > round_config.amount:
raw_maker_amt = round_down(raw_maker_amt, round_config.amount)
maker_amount = to_token_decimals(raw_maker_amt)
taker_amount = to_token_decimals(raw_taker_amt)
return UtilsBuy, maker_amount, taker_amount
elif side == SELL:
raw_maker_amt = round_down(size, round_config.size)
raw_taker_amt = raw_maker_amt * raw_price
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4)
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_down(raw_taker_amt, round_config.amount)
maker_amount = to_token_decimals(raw_maker_amt)
taker_amount = to_token_decimals(raw_taker_amt)
return UtilsSell, maker_amount, taker_amount
else:
raise ValueError(f"order_args.side must be '{BUY}' or '{SELL}'")
def get_market_order_amounts(
self, side: str, amount: float, price: float, round_config: RoundConfig
):
raw_price = round_normal(price, round_config.price)
if side == BUY:
raw_maker_amt = round_down(amount, round_config.size)
raw_taker_amt = raw_maker_amt / raw_price
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4)
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_down(raw_taker_amt, round_config.amount)
maker_amount = to_token_decimals(raw_maker_amt)
taker_amount = to_token_decimals(raw_taker_amt)
return UtilsBuy, maker_amount, taker_amount
elif side == SELL:
raw_maker_amt = round_down(amount, round_config.size)
raw_taker_amt = raw_maker_amt * raw_price
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_up(raw_taker_amt, round_config.amount + 4)
if decimal_places(raw_taker_amt) > round_config.amount:
raw_taker_amt = round_down(raw_taker_amt, round_config.amount)
maker_amount = to_token_decimals(raw_maker_amt)
taker_amount = to_token_decimals(raw_taker_amt)
return UtilsSell, maker_amount, taker_amount
else:
raise ValueError(f"order_args.side must be '{BUY}' or '{SELL}'")
def create_order(
self, order_args: OrderArgs, options: CreateOrderOptions
) -> SignedOrder:
"""
Creates and signs an order
"""
side, maker_amount, taker_amount = self.get_order_amounts(
order_args.side,
order_args.size,
order_args.price,
ROUNDING_CONFIG[options.tick_size],
)
data = OrderData(
maker=self.funder,
taker=order_args.taker,
tokenId=order_args.token_id,
makerAmount=str(maker_amount),
takerAmount=str(taker_amount),
side=side,
feeRateBps=str(order_args.fee_rate_bps),
nonce=str(order_args.nonce),
signer=self.signer.address(),
expiration=str(order_args.expiration),
signatureType=self.sig_type,
)
contract_config = get_contract_config(
self.signer.get_chain_id(), options.neg_risk
)
order_builder = UtilsOrderBuilder(
contract_config.exchange,
self.signer.get_chain_id(),
UtilsSigner(key=self.signer.private_key),
)
return order_builder.build_signed_order(data)
def create_market_order(
self, order_args: MarketOrderArgs, options: CreateOrderOptions
) -> SignedOrder:
"""
Creates and signs a market order
"""
side, maker_amount, taker_amount = self.get_market_order_amounts(
order_args.side,
order_args.amount,
order_args.price,
ROUNDING_CONFIG[options.tick_size],
)
data = OrderData(
maker=self.funder,
taker=order_args.taker,
tokenId=order_args.token_id,
makerAmount=str(maker_amount),
takerAmount=str(taker_amount),
side=side,
feeRateBps=str(order_args.fee_rate_bps),
nonce=str(order_args.nonce),
signer=self.signer.address(),
expiration="0",
signatureType=self.sig_type,
)
contract_config = get_contract_config(
self.signer.get_chain_id(), options.neg_risk
)
order_builder = UtilsOrderBuilder(
contract_config.exchange,
self.signer.get_chain_id(),
UtilsSigner(key=self.signer.private_key),
)
return order_builder.build_signed_order(data)
def calculate_buy_market_price(
self,
positions: list[OrderSummary],
amount_to_match: float,
order_type: OrderType,
) -> float:
if not positions:
raise Exception("no match")
sum = 0
for p in reversed(positions):
sum += float(p.size) * float(p.price)
if sum >= amount_to_match:
return float(p.price)
if order_type == OrderType.FOK:
raise Exception("no match")
return float(positions[0].price)
def calculate_sell_market_price(
self,
positions: list[OrderSummary],
amount_to_match: float,
order_type: OrderType,
) -> float:
if not positions:
raise Exception("no match")
sum = 0
for p in reversed(positions):
sum += float(p.size)
if sum >= amount_to_match:
return float(p.price)
if order_type == OrderType.FOK:
raise Exception("no match")
return float(positions[0].price)
================================================
FILE: py_clob_client/order_builder/constants.py
================================================
BUY = "BUY"
SELL = "SELL"
================================================
FILE: py_clob_client/order_builder/helpers.py
================================================
from math import floor, ceil
from decimal import Decimal
def round_down(x: float, sig_digits: int) -> float:
return floor(x * (10**sig_digits)) / (10**sig_digits)
def round_normal(x: float, sig_digits: int) -> float:
return round(x * (10**sig_digits)) / (10**sig_digits)
def round_up(x: float, sig_digits: int) -> float:
return ceil(x * (10**sig_digits)) / (10**sig_digits)
def to_token_decimals(x: float) -> int:
f = (10**6) * x
if decimal_places(f) > 0:
f = round_normal(f, 0)
return int(f)
def decimal_places(x: float) -> int:
return abs(Decimal(x.__str__()).as_tuple().exponent)
================================================
FILE: py_clob_client/rfq/__init__.py
================================================
from .rfq_types import (
# Input types
RfqUserRequest,
RfqUserQuote,
CreateRfqRequestParams,
CreateRfqQuoteParams,
CancelRfqRequestParams,
CancelRfqQuoteParams,
AcceptQuoteParams,
ApproveOrderParams,
GetRfqRequestsParams,
GetRfqQuotesParams,
GetRfqBestQuoteParams,
# Response types
RfqRequest,
RfqQuote,
RfqRequestResponse,
RfqQuoteResponse,
RfqPaginatedResponse,
)
from .rfq_helpers import (
parse_units,
to_camel_case,
parse_rfq_requests_params,
parse_rfq_quotes_params,
COLLATERAL_TOKEN_DECIMALS,
CONDITIONAL_TOKEN_DECIMALS,
)
from .rfq_client import RfqClient
__all__ = [
# Client
"RfqClient",
# Input types
"RfqUserRequest",
"RfqUserQuote",
"CreateRfqRequestParams",
"CreateRfqQuoteParams",
"CancelRfqRequestParams",
"CancelRfqQuoteParams",
"AcceptQuoteParams",
"ApproveOrderParams",
"GetRfqRequestsParams",
"GetRfqQuotesParams",
"GetRfqBestQuoteParams",
# Response types
"RfqRequest",
"RfqQuote",
"RfqRequestResponse",
"RfqQuoteResponse",
"RfqPaginatedResponse",
# Helpers
"parse_units",
"to_camel_case",
"parse_rfq_requests_params",
"parse_rfq_quotes_params",
"COLLATERAL_TOKEN_DECIMALS",
"CONDITIONAL_TOKEN_DECIMALS",
]
================================================
FILE: py_clob_client/rfq/rfq_client.py
================================================
"""
RFQ (Request for Quote) client for the Polymarket CLOB API.
This module provides the RfqClient class which handles all RFQ operations
including creating requests, quotes, and executing trades.
"""
import logging
import json
from urllib.parse import urlencode
from typing import Optional, Any, TYPE_CHECKING
from ..clob_types import RequestArgs, OrderArgs, PartialCreateOrderOptions
from ..headers.headers import create_level_2_headers
from ..http_helpers.helpers import get, post, delete
from ..order_builder.builder import ROUNDING_CONFIG
from ..order_builder.helpers import round_normal, round_down
from ..order_builder.constants import BUY, SELL
from ..endpoints import (
CREATE_RFQ_REQUEST,
CANCEL_RFQ_REQUEST,
GET_RFQ_REQUESTS,
CREATE_RFQ_QUOTE,
CANCEL_RFQ_QUOTE,
GET_RFQ_REQUESTER_QUOTES,
GET_RFQ_QUOTER_QUOTES,
GET_RFQ_BEST_QUOTE,
RFQ_REQUESTS_ACCEPT,
RFQ_QUOTE_APPROVE,
RFQ_CONFIG,
)
from .rfq_types import (
RfqUserRequest,
RfqUserQuote,
CancelRfqRequestParams,
CancelRfqQuoteParams,
AcceptQuoteParams,
ApproveOrderParams,
GetRfqRequestsParams,
GetRfqQuotesParams,
GetRfqBestQuoteParams,
MatchType,
)
from .rfq_helpers import (
parse_units,
parse_rfq_requests_params,
parse_rfq_quotes_params,
COLLATERAL_TOKEN_DECIMALS,
)
if TYPE_CHECKING:
from ..client import ClobClient
class RfqClient:
"""
RFQ client for creating and managing RFQ requests and quotes.
This client is typically accessed via the parent ClobClient's `rfq` attribute:
client = ClobClient(host, chain_id, key, creds)
response = client.rfq.create_rfq_request(user_request)
"""
def __init__(self, parent: "ClobClient"):
"""
Initialize the RFQ client.
Args:
parent: The parent ClobClient instance providing auth and config.
"""
self._parent = parent
self.logger = logging.getLogger(self.__class__.__name__)
def _ensure_l2_auth(self) -> None:
"""
Verify that L2 authentication is available.
Raises:
PolyException: If signer or creds are not configured.
"""
self._parent.assert_level_2_auth()
def _get_l2_headers(self, method: str, endpoint: str, body: Any = None, serialized_body: Any = None) -> dict:
"""
Create L2 authentication headers for a request.
Args:
method: HTTP method (GET, POST, PUT, DELETE)
endpoint: API endpoint path
body: Optional request body
Returns:
Dictionary of authentication headers.
"""
request_args = RequestArgs(method=method, request_path=endpoint, body=body)
if serialized_body is not None:
request_args.serialized_body = serialized_body
return create_level_2_headers(
self._parent.signer,
self._parent.creds,
request_args,
)
def _build_url(self, endpoint: str) -> str:
"""Build full URL from endpoint."""
return f"{self._parent.host}{endpoint}"
# =========================================================================
# Request-side methods
# =========================================================================
def create_rfq_request(
self,
user_request: RfqUserRequest,
options: Optional[PartialCreateOrderOptions] = None,
) -> dict:
"""
Create and post an RFQ request from a user request.
This method:
1. Resolves the tick size for the token
2. Rounds price and size according to tick size rules
3. Calculates amount_in and amount_out based on side
4. Posts the request to the server
Args:
user_order: Simplified order with token_id, price, side, size
options: Optional tick size override
Returns:
Response dict with request_id on success.
Example:
>>> response = client.rfq.create_rfq_request(
... RfqUserRequest(
... token_id="123...",
... price=0.5,
... side="BUY",
... size=40,
... )
... )
"""
token_id = user_request.token_id
price = user_request.price
side = user_request.side
size = user_request.size
# Resolve tick size (from options or fetch from server)
tick_size = self._parent._ClobClient__resolve_tick_size(
token_id,
options.tick_size if options else None,
)
# Get rounding configuration (ensure tick_size is a string for lookup)
tick_size_str = str(tick_size) if not isinstance(tick_size, str) else tick_size
round_config = ROUNDING_CONFIG[tick_size_str]
# Round price and size
rounded_price = round_normal(price, round_config.price)
rounded_size = round_down(size, round_config.size)
# Format with correct decimal places
price_decimals = int(round_config.price)
size_decimals = int(round_config.size)
amount_decimals = int(round_config.amount)
rounded_price_str = f"{rounded_price:.{price_decimals}f}"
rounded_size_str = f"{rounded_size:.{size_decimals}f}"
# Parse back to numbers for calculation
size_num = float(rounded_size_str)
price_num = float(rounded_price_str)
# Get signature type from parent's order builder
user_type = self._parent.builder.sig_type
# Calculate amounts based on side
if side == BUY:
# Buying tokens: pay USDC, receive tokens
# asset_in = tokens (what requester receives)
# asset_out = USDC (what requester pays)
amount_in = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS)
usdc_amount = size_num * price_num
usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}"
amount_out = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS)
asset_in = token_id
asset_out = "0" # USDC
else:
# Selling tokens: pay tokens, receive USDC
# asset_in = USDC (what requester receives)
# asset_out = tokens (what requester pays)
usdc_amount = size_num * price_num
usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}"
amount_in = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS)
amount_out = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS)
asset_in = "0" # USDC
asset_out = token_id
# Post directly to the server
self._ensure_l2_auth()
body = {
"assetIn": asset_in,
"assetOut": asset_out,
"amountIn": str(amount_in),
"amountOut": str(amount_out),
"userType": user_type,
}
serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("POST", CREATE_RFQ_REQUEST, body, serialized_body)
return post(self._build_url(CREATE_RFQ_REQUEST), headers=headers, data=serialized_body)
def cancel_rfq_request(self, params: CancelRfqRequestParams) -> str:
"""
Cancel an RFQ request.
Args:
params: Contains request_id to cancel.
Returns:
"OK" on success.
"""
self._ensure_l2_auth()
body = {"requestId": params.request_id}
serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("DELETE", CANCEL_RFQ_REQUEST, body, serialized_body)
return delete(self._build_url(CANCEL_RFQ_REQUEST), headers=headers, data=serialized_body)
def get_rfq_requests(
self, params: Optional[GetRfqRequestsParams] = None
) -> dict:
"""
Get RFQ requests with optional filtering.
Args:
params: Optional filter parameters.
Returns:
Paginated response with RFQ requests.
"""
self._ensure_l2_auth()
headers = self._get_l2_headers("GET", GET_RFQ_REQUESTS)
query_params = parse_rfq_requests_params(params)
# Build URL with query params
url = self._build_url(GET_RFQ_REQUESTS)
if query_params:
# Use doseq=True so list values become repeated query params:
# requestIds=id1&requestIds=id2
url = f"{url}?{urlencode(query_params, doseq=True)}"
return get(url, headers=headers)
# =========================================================================
# Quote-side methods
# =========================================================================
def create_rfq_quote(
self,
user_quote: RfqUserQuote,
options: Optional[PartialCreateOrderOptions] = None,
) -> dict:
"""
Create and post an RFQ quote in response to an RFQ request.
This method:
1. Fetches the RFQ request to get token_id
2. Resolves the tick size for the token
3. Rounds price and size according to tick size rules
4. Calculates amount_in and amount_out based on side
5. Posts the quote to the server
Args:
user_quote: Simplified quote with request_id, token_id, price, side, size
options: Optional tick size override
Returns:
Response dict with quote_id on success.
Example:
>>> response = client.rfq.create_rfq_quote(
... RfqUserQuote(
... request_id="019a83a9-f4c7-7c96-9139-2da2b2d934ef",
... token_id="123...",
... price=0.5,
... side="SELL",
... size=100.0,
... )
... )
"""
request_id = user_quote.request_id
token_id = user_quote.token_id
price = user_quote.price
side = user_quote.side
size = user_quote.size
# Resolve tick size (from options or fetch from server)
tick_size = self._parent._ClobClient__resolve_tick_size(
token_id,
options.tick_size if options else None,
)
# Get rounding configuration (ensure tick_size is a string for lookup)
tick_size_str = str(tick_size) if not isinstance(tick_size, str) else tick_size
round_config = ROUNDING_CONFIG[tick_size_str]
# Round price and size
rounded_price = round_normal(price, round_config.price)
rounded_size = round_down(size, round_config.size)
# Format with correct decimal places
price_decimals = int(round_config.price)
size_decimals = int(round_config.size)
amount_decimals = int(round_config.amount)
rounded_price_str = f"{rounded_price:.{price_decimals}f}"
rounded_size_str = f"{rounded_size:.{size_decimals}f}"
# Parse back to numbers for calculation
size_num = float(rounded_size_str)
price_num = float(rounded_price_str)
# Get signature type from parent's order builder
user_type = self._parent.builder.sig_type
# Calculate amounts based on side
if side == BUY:
# Buying tokens: pay USDC, receive tokens
# asset_in = tokens (what quoter receives)
# asset_out = USDC (what quoter pays)
amount_in = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS)
usdc_amount = size_num * price_num
usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}"
amount_out = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS)
asset_in = token_id
asset_out = "0" # USDC
else:
# Selling tokens: pay tokens, receive USDC
# asset_in = USDC (what quoter receives)
# asset_out = tokens (what quoter pays)
usdc_amount = size_num * price_num
usdc_amount_str = f"{usdc_amount:.{amount_decimals}f}"
amount_in = parse_units(usdc_amount_str, COLLATERAL_TOKEN_DECIMALS)
amount_out = parse_units(rounded_size_str, COLLATERAL_TOKEN_DECIMALS)
asset_in = "0" # USDC
asset_out = token_id
# Post directly to the server
self._ensure_l2_auth()
body = {
"requestId": request_id,
"assetIn": asset_in,
"assetOut": asset_out,
"amountIn": str(amount_in),
"amountOut": str(amount_out),
"userType": user_type,
}
serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("POST", CREATE_RFQ_QUOTE, body, serialized_body)
return post(self._build_url(CREATE_RFQ_QUOTE), headers=headers, data=serialized_body)
def get_rfq_requester_quotes(self, params: Optional[GetRfqQuotesParams] = None) -> dict:
"""
Get quotes on requests created by the authenticated user (requester view).
Returns quotes that others have made on your RFQ requests.
Args:
params: Optional filter parameters.
Returns:
Paginated response with RFQ quotes.
"""
self._ensure_l2_auth()
headers = self._get_l2_headers("GET", GET_RFQ_REQUESTER_QUOTES)
query_params = parse_rfq_quotes_params(params)
# Build URL with query params
url = self._build_url(GET_RFQ_REQUESTER_QUOTES)
if query_params:
url = f"{url}?{urlencode(query_params, doseq=True)}"
return get(url, headers=headers)
def get_rfq_quoter_quotes(self, params: Optional[GetRfqQuotesParams] = None) -> dict:
"""
Get quotes created by the authenticated user (quoter view).
Returns quotes that you have made on others' RFQ requests.
Args:
params: Optional filter parameters.
Returns:
Paginated response with RFQ quotes.
"""
self._ensure_l2_auth()
headers = self._get_l2_headers("GET", GET_RFQ_QUOTER_QUOTES)
query_params = parse_rfq_quotes_params(params)
# Build URL with query params
url = self._build_url(GET_RFQ_QUOTER_QUOTES)
if query_params:
url = f"{url}?{urlencode(query_params, doseq=True)}"
return get(url, headers=headers)
def get_rfq_best_quote(
self, params: Optional[GetRfqBestQuoteParams] = None
) -> dict:
"""
Get the best quote for an RFQ request.
Args:
params: Contains request_id.
Returns:
Single quote object representing the best quote.
"""
self._ensure_l2_auth()
headers = self._get_l2_headers("GET", GET_RFQ_BEST_QUOTE)
url = self._build_url(GET_RFQ_BEST_QUOTE)
if params and params.request_id:
url = f"{url}?{urlencode({'requestId': params.request_id})}"
return get(url, headers=headers)
def cancel_rfq_quote(self, params: CancelRfqQuoteParams) -> str:
"""
Cancel an RFQ quote.
Args:
params: Contains quote_id to cancel.
Returns:
"OK" on success.
"""
self._ensure_l2_auth()
body = {"quoteId": params.quote_id}
serialized_body = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("DELETE", CANCEL_RFQ_QUOTE, body, serialized_body)
return delete(self._build_url(CANCEL_RFQ_QUOTE), headers=headers, data=serialized_body)
# =========================================================================
# Trade execution methods
# =========================================================================
def accept_rfq_quote(self, params: AcceptQuoteParams) -> str:
"""
Accept an RFQ quote (requester side).
This method:
1. Fetches the RFQ quote details
2. Creates a signed order matching the quote
3. Submits the acceptance with the order
Args:
params: Contains request_id, quote_id, and expiration.
Returns:
"OK" on success.
"""
self._ensure_l2_auth()
resp = self.get_rfq_requester_quotes(
GetRfqQuotesParams(quote_ids=[params.quote_id])
)
if not resp.get("data") or len(resp["data"]) == 0:
raise Exception("RFQ quote not found")
rfq_quote = resp["data"][0]
order_creation_payload = self._get_request_order_creation_payload(rfq_quote)
price = order_creation_payload.get("price")
side = order_creation_payload["side"]
size = float(order_creation_payload["size"])
token = order_creation_payload["token"]
order_args = OrderArgs(
token_id=token,
price=price,
size=size,
side=side,
expiration=params.expiration,
)
order = self._parent.create_order(order_args)
if not order:
raise Exception("Error creating order")
order_dict = order.dict()
accept_payload = {
"requestId": params.request_id,
"quoteId": params.quote_id,
"owner": self._parent.creds.api_key,
# Order fields from dict
"salt": int(order_dict["salt"]),
"maker": order_dict["maker"],
"signer": order_dict["signer"],
"taker": order_dict["taker"],
"tokenId": order_dict["tokenId"],
"makerAmount": order_dict["makerAmount"],
"takerAmount": order_dict["takerAmount"],
"expiration": int(order_dict["expiration"]),
"nonce": order_dict["nonce"],
"feeRateBps": order_dict["feeRateBps"],
"side": side,
"signatureType": int(order_dict["signatureType"]),
"signature": order_dict["signature"],
}
self.logger.debug(
"Accept payload: requestId=%s, quoteId=%s, tokenId=%s, side=%s",
accept_payload.get("requestId"),
accept_payload.get("quoteId"),
accept_payload.get("tokenId"),
accept_payload.get("side"),
)
serialized_body = json.dumps(accept_payload, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("POST", RFQ_REQUESTS_ACCEPT, accept_payload, serialized_body)
return post(
self._build_url(RFQ_REQUESTS_ACCEPT),
headers=headers,
data=serialized_body,
)
def approve_rfq_order(self, params: ApproveOrderParams) -> str:
"""
Approve an RFQ order (quoter side).
This method:
1. Fetches the RFQ quote details
2. Creates a signed order based on quote parameters
3. Submits the approval with the order
Args:
params: Contains request_id, quote_id, and expiration.
Returns:
"OK" on success.
"""
self._ensure_l2_auth()
# Step 1: Fetch the RFQ quote
rfq_quotes = self.get_rfq_quoter_quotes(
GetRfqQuotesParams(quote_ids=[params.quote_id])
)
if not rfq_quotes.get("data") or len(rfq_quotes["data"]) == 0:
raise Exception("RFQ quote not found")
rfq_quote = rfq_quotes["data"][0]
# Step 2: Create an order based on quote details
# Quoter uses their own quote's side
side = rfq_quote.get("side", BUY)
# Determine size based on quote side
if side == BUY:
size = rfq_quote.get("sizeIn")
else:
size = rfq_quote.get("sizeOut")
token_id = rfq_quote.get("token")
price = rfq_quote.get("price")
order_args = OrderArgs(
token_id=token_id,
price=float(price),
size=float(size),
side=side,
expiration=params.expiration,
)
order = self._parent.create_order(order_args)
if not order:
raise Exception("Error creating order")
# Step 3: Build approve payload
order_dict = order.dict()
approve_payload = {
"requestId": params.request_id,
"quoteId": params.quote_id,
"owner": self._parent.creds.api_key,
# Order fields from dict
"salt": int(order_dict["salt"]),
"maker": order_dict["maker"],
"signer": order_dict["signer"],
"taker": order_dict["taker"],
"tokenId": order_dict["tokenId"],
"makerAmount": order_dict["makerAmount"],
"takerAmount": order_dict["takerAmount"],
"expiration": int(order_dict["expiration"]),
"nonce": order_dict["nonce"],
"feeRateBps": order_dict["feeRateBps"],
"side": side,
"signatureType": int(order_dict["signatureType"]),
"signature": order_dict["signature"],
}
serialized_body = json.dumps(approve_payload, separators=(",", ":"), ensure_ascii=False)
headers = self._get_l2_headers("POST", RFQ_QUOTE_APPROVE, approve_payload, serialized_body)
return post(
self._build_url(RFQ_QUOTE_APPROVE),
headers=headers,
data=serialized_body,
)
# =========================================================================
# Configuration
# =========================================================================
def rfq_config(self) -> dict:
"""
Get RFQ configuration from the server.
Returns:
Configuration object with RFQ system parameters.
"""
self._ensure_l2_auth()
headers = self._get_l2_headers("GET", RFQ_CONFIG)
return get(self._build_url(RFQ_CONFIG), headers=headers)
def _get_request_order_creation_payload(self, quote: dict) -> dict:
"""
Build the order creation payload for an RFQ request based on quote details.
"""
raw_match_type = quote.get("matchType", MatchType.COMPLEMENTARY)
match_type = (
raw_match_type
if isinstance(raw_match_type, MatchType)
else MatchType(str(raw_match_type))
)
side = quote.get("side", BUY)
if match_type == MatchType.COMPLEMENTARY:
# For BUY <> SELL and SELL <> BUY
# the order side is opposite the quote side
token = quote.get("token")
if not token:
raise Exception("missing token for COMPLEMENTARY match")
side = SELL if side == BUY else BUY
size = quote.get("sizeOut") if side == BUY else quote.get("sizeIn")
if size is None:
raise Exception("missing sizeIn/sizeOut for COMPLEMENTARY match")
price = quote.get("price")
if price is None:
raise Exception("missing price for COMPLEMENTARY match")
price = float(price)
return {
"token": token,
"side": side,
"size": size,
"price": price,
}
elif match_type in (MatchType.MINT, MatchType.MERGE):
# BUY<> BUY, SELL <> SELL
# the order side is the same as the quote side
token = quote.get("complement")
if not token:
raise Exception("missing complement token for MINT/MERGE match")
size = quote.get("sizeIn") if side == BUY else quote.get("sizeOut")
if size is None:
raise Exception("missing sizeIn/sizeOut for MINT/MERGE match")
price = quote.get("price")
if price is None:
raise Exception("missing price for MINT/MERGE match")
price = float(price)
# For a MINT or a MERGE, the requester price is the inverse of the quote price
# 95c Quote to BUY NO, implies that the Requester is buying YES at 5c
# 45c Quote to SELL NO, implies the Requester is selling YES at 55c
price = 1 - price
return {
"token": token,
"side": side,
"size": size,
"price": price,
}
else:
raise Exception(f"invalid match type: {raw_match_type}")
================================================
FILE: py_clob_client/rfq/rfq_helpers.py
================================================
"""
RFQ helper functions for the Polymarket CLOB API.
This module provides utility functions for RFQ operations including
query parameter parsing and unit conversion.
"""
from typing import Optional, Dict, Any
from .rfq_types import GetRfqRequestsParams, GetRfqQuotesParams
# Token decimals constants
COLLATERAL_TOKEN_DECIMALS = 6 # USDC has 6 decimals
CONDITIONAL_TOKEN_DECIMALS = 6
def parse_units(value: str, decimals: int) -> int:
"""
Convert a decimal string to smallest units (like wei for ETH).
Args:
value: Decimal string (e.g., "1.5")
decimals: Number of decimal places (e.g., 6 for USDC)
Returns:
Integer in smallest units (e.g., 1500000 for "1.5" with 6 decimals)
Examples:
>>> parse_units("1.5", 6)
1500000
>>> parse_units("100", 6)
100000000
>>> parse_units("0.000001", 6)
1
"""
if "." in value:
integer_part, decimal_part = value.split(".")
# Pad or truncate decimal part to match decimals
decimal_part = decimal_part[:decimals].ljust(decimals, "0")
return int(integer_part + decimal_part)
else:
return int(value) * (10**decimals)
def to_camel_case(snake_str: str) -> str:
"""
Convert snake_case string to camelCase.
Args:
snake_str: String in snake_case format
Returns:
String in camelCase format
Examples:
>>> to_camel_case("user_address")
'userAddress'
>>> to_camel_case("request_id")
'requestId'
>>> to_camel_case("size_usdc_min")
'sizeUsdcMin'
"""
components = snake_str.split("_")
return components[0] + "".join(x.title() for x in components[1:])
def parse_rfq_requests_params(params: Optional[GetRfqRequestsParams] = None) -> Dict[str, Any]:
"""
Convert GetRfqRequestsParams to query string parameters.
Arrays are kept as Python lists so the caller can serialize them with
`urllib.parse.urlencode(..., doseq=True)` (repeated query params).
Args:
params: Optional filter parameters
Returns:
Dictionary of query parameters ready for HTTP request
"""
if params is None:
return {}
result = {}
# Single value fields (convert snake_case to camelCase)
single_fields = [
("state", "state"),
("size_min", "sizeMin"),
("size_max", "sizeMax"),
("size_usdc_min", "sizeUsdcMin"),
("size_usdc_max", "sizeUsdcMax"),
("price_min", "priceMin"),
("price_max", "priceMax"),
("sort_by", "sortBy"),
("sort_dir", "sortDir"),
("limit", "limit"),
("offset", "offset"),
]
for python_name, api_name in single_fields:
value = getattr(params, python_name, None)
if value is not None:
result[api_name] = value
# Array fields (keep as lists; let urlencode(doseq=True) expand them)
if params.request_ids:
result["requestIds"] = params.request_ids
if params.markets:
result["markets"] = params.markets
return result
def parse_rfq_quotes_params(params: Optional[GetRfqQuotesParams] = None) -> Dict[str, Any]:
"""
Convert GetRfqQuotesParams to query string parameters.
Arrays are kept as Python lists so the caller can serialize them with
`urllib.parse.urlencode(..., doseq=True)` (repeated query params).
Args:
params: Optional filter parameters
Returns:
Dictionary of query parameters ready for HTTP request
"""
if params is None:
return {}
result = {}
# Single value fields (convert snake_case to camelCase)
single_fields = [
("state", "state"),
("size_min", "sizeMin"),
("size_max", "sizeMax"),
("size_usdc_min", "sizeUsdcMin"),
("size_usdc_max", "sizeUsdcMax"),
("price_min", "priceMin"),
("price_max", "priceMax"),
("sort_by", "sortBy"),
("sort_dir", "sortDir"),
("limit", "limit"),
("offset", "offset"),
]
for python_name, api_name in single_fields:
value = getattr(params, python_name, None)
if value is not None:
result[api_name] = value
# Array fields (keep as lists; let urlencode(doseq=True) expand them)
if params.quote_ids:
result["quoteIds"] = params.quote_ids
if params.request_ids:
result["requestIds"] = params.request_ids
if params.markets:
result["markets"] = params.markets
return result
================================================
FILE: py_clob_client/rfq/rfq_types.py
================================================
"""
RFQ (Request for Quote) data types for the Polymarket CLOB API.
This module defines all input and response types used by the RFQ client.
"""
from dataclasses import dataclass, field
from typing import List, Optional, Any, Literal
from enum import Enum
# =============================================================================
# Input Types
# =============================================================================
@dataclass
class RfqUserRequest:
"""
Simplified user input for creating an RFQ request.
This is the user-facing order format that gets converted to
CreateRfqRequestParams for the API.
"""
token_id: str
"""Token ID of the conditional token being traded."""
price: float
"""Price per token (0 < price < 1)."""
side: str
"""Order side: "BUY" or "SELL"."""
size: float
"""Size in conditional tokens."""
@dataclass
class RfqUserQuote:
"""
Simplified user input for creating an RFQ quote.
This is the user-facing quote format that gets converted to
CreateRfqQuoteParams for the API.
"""
request_id: str
"""ID of the RFQ request being quoted."""
token_id: str
"""Token ID of the conditional token being traded."""
price: float
"""Price per token (0 < price < 1)."""
side: str
"""Quoter's side: "BUY" or "SELL"."""
size: float
"""Size in conditional tokens."""
@dataclass
class CreateRfqRequestParams:
"""
Server payload for creating an RFQ request.
This is the format sent to the API after converting from RfqUserRequest.
"""
asset_in: str
"""Asset being received (token ID or "0" for USDC)."""
asset_out: str
"""Asset being paid (token ID or "0" for USDC)."""
amount_in: str
"""Amount being received (in smallest units, as string)."""
amount_out: str
"""Amount being paid (in smallest units, as string)."""
user_type: int
"""Signature type (0=EOA, 1=POLY_PROXY, 2=POLY_GNOSIS_SAFE)."""
@dataclass
class CreateRfqQuoteParams:
"""
Parameters for creating a quote in response to an RFQ request.
"""
request_id: str
"""ID of the RFQ request being quoted."""
asset_in: str
"""Asset the quoter is paying."""
asset_out: str
"""Asset the quoter is receiving."""
amount_in: str
"""Amount quoter is paying (in smallest units)."""
amount_out: str
"""Amount quoter is receiving (in smallest units)."""
# Note: user_type is auto-filled by the client
@dataclass
class CancelRfqRequestParams:
"""
Parameters for canceling an RFQ request.
"""
request_id: str
"""ID of the request to cancel."""
@dataclass
class CancelRfqQuoteParams:
"""
Parameters for canceling an RFQ quote.
"""
quote_id: str
"""ID of the quote to cancel."""
@dataclass
class AcceptQuoteParams:
"""
Parameters for accepting a quote (requester side).
When a requester accepts a quote, they create a signed order
and submit it with this payload.
"""
request_id: str
"""ID of the RFQ request."""
quote_id: str
"""ID of the quote being accepted."""
expiration: int
"""Unix timestamp for order expiration."""
@dataclass
class ApproveOrderParams:
"""
Parameters for approving an order (quoter side).
When a quoter's quote is accepted, they approve by creating
a signed order and submitting it with this payload.
"""
request_id: str
"""ID of the RFQ request."""
quote_id: str
"""ID of the quote being approved."""
expiration: int
"""Unix timestamp for order expiration."""
@dataclass
class GetRfqRequestsParams:
"""
Query parameters for fetching RFQ requests.
All fields are optional filters.
"""
request_ids: Optional[List[str]] = None
"""Filter by specific request IDs (query param: requestIds; repeatable)."""
state: Optional[Literal["active", "inactive"]] = None
"""Single state filter ("active" or "inactive")."""
markets: Optional[List[str]] = None
"""Filter by market condition IDs (query param: markets; repeatable)."""
size_min: Optional[float] = None
"""Minimum size filter."""
size_max: Optional[float] = None
"""Maximum size filter."""
size_usdc_min: Optional[float] = None
"""Minimum USDC size filter."""
size_usdc_max: Optional[float] = None
"""Maximum USDC size filter."""
price_min: Optional[float] = None
"""Minimum price filter."""
price_max: Optional[float] = None
"""Maximum price filter."""
sort_by: Optional[Literal["price", "expiry", "size", "created"]] = None
"""Field to sort by."""
sort_dir: Optional[Literal["asc", "desc"]] = None
"""Sort direction: "asc" or "desc"."""
limit: Optional[int] = None
"""Pagination limit."""
offset: Optional[str] = None
"""Pagination cursor (base64 encoded)."""
@dataclass
class GetRfqQuotesParams:
"""
Query parameters for fetching RFQ quotes.
All fields are optional filters.
"""
quote_ids: Optional[List[str]] = None
"""Filter by specific quote IDs (query param: quoteIds; repeatable)."""
request_ids: Optional[List[str]] = None
"""Filter by request IDs (query param: requestIds; repeatable)."""
state: Optional[Literal["active", "inactive"]] = None
"""Single state filter ("active" or "inactive")."""
markets: Optional[List[str]] = None
"""Filter by market condition IDs (query param: markets; repeatable)."""
size_min: Optional[float] = None
"""Minimum size filter."""
size_max: Optional[float] = None
"""Maximum size filter."""
size_usdc_min: Optional[float] = None
"""Minimum USDC size filter."""
size_usdc_max: Optional[float] = None
"""Maximum USDC size filter."""
price_min: Optional[float] = None
"""Minimum price filter."""
price_max: Optional[float] = None
"""Maximum price filter."""
sort_by: Optional[Literal["price", "expiry", "created"]] = None
"""Field to sort by."""
sort_dir: Optional[Literal["asc", "desc"]] = None
"""Sort direction: "asc" or "desc"."""
limit: Optional[int] = None
"""Pagination limit."""
offset: Optional[str] = None
"""Pagination cursor (base64 encoded)."""
@dataclass
class GetRfqBestQuoteParams:
"""
Parameters for fetching the best quote for a request.
"""
request_id: Optional[str] = None
"""Request ID to get best quote for."""
# =============================================================================
# Response Types
# =============================================================================
@dataclass
class RfqRequest:
"""
Full RFQ request object returned by the API.
"""
request_id: str
"""Unique request identifier."""
user_address: str
"""Address of the requester."""
proxy_address: Optional[str] = None
"""Proxy address if applicable."""
token: Optional[str] = None
"""Token ID being traded."""
complement: Optional[str] = None
"""Complement token ID."""
condition: Optional[str] = None
"""Condition ID (market)."""
side: Optional[str] = None
"""Order side: "BUY" or "SELL"."""
size_in: Optional[str] = None
"""Size of asset_in."""
size_out: Optional[str] = None
"""Size of asset_out."""
price: Optional[float] = None
"""Price."""
accepted_quote_id: Optional[str] = None
"""ID of accepted quote (if any)."""
state: Optional[str] = None
"""Request state."""
expiry: Optional[str] = None
"""Expiration timestamp."""
created_at: Optional[str] = None
"""Creation timestamp."""
updated_at: Optional[str] = None
"""Last update timestamp."""
@dataclass
class RfqQuote:
"""
Full RFQ quote object returned by the API.
"""
quote_id: str
"""Unique quote identifier."""
request_id: str
"""Associated request ID."""
user_address: str
"""Address of the quoter."""
proxy_address: Optional[str] = None
"""Proxy address if applicable."""
complement: Optional[str] = None
"""Complement token ID."""
condition: Optional[str] = None
"""Condition ID (market)."""
token: Optional[str] = None
"""Token ID."""
side: Optional[str] = None
"""Quote side: "BUY" or "SELL"."""
size_in: Optional[str] = None
"""Size of asset_in."""
size_out: Optional[str] = None
"""Size of asset_out."""
price: Optional[float] = None
"""Quote price."""
state: Optional[str] = None
"""Quote state."""
expiry: Optional[str] = None
"""Expiration timestamp."""
created_at: Optional[str] = None
"""Creation timestamp."""
updated_at: Optional[str] = None
"""Last update timestamp."""
@dataclass
class RfqRequestResponse:
"""
Response from creating an RFQ request.
"""
request_id: Optional[str] = None
"""Created request ID."""
error: Optional[str] = None
"""Error message if failed."""
@dataclass
class RfqQuoteResponse:
"""
Response from creating an RFQ quote.
"""
quote_id: Optional[str] = None
"""Created quote ID."""
error: Optional[str] = None
"""Error message if failed."""
@dataclass
class RfqPaginatedResponse:
"""
Paginated response for list queries.
"""
data: List[Any] = field(default_factory=list)
"""Array of results (RfqRequest or RfqQuote objects)."""
next_cursor: Optional[str] = None
"""Cursor for next page."""
limit: Optional[int] = None
"""Page limit."""
count: Optional[int] = None
"""Number of results in this page."""
total_count: Optional[int] = None
"""Total count (optional)."""
class MatchType(str, Enum):
COMPLEMENTARY = "COMPLEMENTARY"
MINT = "MINT"
MERGE = "MERGE"
================================================
FILE: py_clob_client/signer.py
================================================
from eth_account import Account
class Signer:
def __init__(self, private_key: str, chain_id: int):
assert private_key is not None and chain_id is not None
self.private_key = private_key
self.account = Account.from_key(private_key)
self.chain_id = chain_id
def address(self):
return self.account.address
def get_chain_id(self):
return self.chain_id
def sign(self, message_hash):
"""
Signs a message hash
"""
return Account._sign_hash(message_hash, self.private_key).signature.hex()
================================================
FILE: py_clob_client/signing/__init__.py
================================================
================================================
FILE: py_clob_client/signing/eip712.py
================================================
from poly_eip712_structs import make_domain
from eth_utils import keccak
from py_order_utils.utils import prepend_zx
from .model import ClobAuth
from ..signer import Signer
CLOB_DOMAIN_NAME = "ClobAuthDomain"
CLOB_VERSION = "1"
MSG_TO_SIGN = "This message attests that I control the given wallet"
def get_clob_auth_domain(chain_id: int):
return make_domain(name=CLOB_DOMAIN_NAME, version=CLOB_VERSION, chainId=chain_id)
def sign_clob_auth_message(signer: Signer, timestamp: int, nonce: int) -> str:
clob_auth_msg = ClobAuth(
address=signer.address(),
timestamp=str(timestamp),
nonce=nonce,
message=MSG_TO_SIGN,
)
chain_id = signer.get_chain_id()
auth_struct_hash = prepend_zx(
keccak(clob_auth_msg.signable_bytes(get_clob_auth_domain(chain_id))).hex()
)
return prepend_zx(signer.sign(auth_struct_hash))
================================================
FILE: py_clob_client/signing/hmac.py
================================================
import hmac
import hashlib
import base64
def build_hmac_signature(
secret: str, timestamp: str, method: str, requestPath: str, body=None
):
"""
Creates an HMAC signature by signing a payload with the secret
"""
base64_secret = base64.urlsafe_b64decode(secret)
message = str(timestamp) + str(method) + str(requestPath)
if body:
# NOTE: Necessary to replace single quotes with double quotes
# to generate the same hmac message as go and typescript
message += str(body).replace("'", '"')
h = hmac.new(base64_secret, bytes(message, "utf-8"), hashlib.sha256)
# ensure base64 encoded
return (base64.urlsafe_b64encode(h.digest())).decode("utf-8")
================================================
FILE: py_clob_client/signing/model.py
================================================
from poly_eip712_structs import EIP712Struct, Address, String, Uint
class ClobAuth(EIP712Struct):
address = Address()
timestamp = String()
nonce = Uint()
message = String()
================================================
FILE: py_clob_client/utilities.py
================================================
import hashlib
import json
from .clob_types import OrderBookSummary, OrderSummary, TickSize
def parse_raw_orderbook_summary(raw_obs: any) -> OrderBookSummary:
bids = []
for bid in raw_obs["bids"]:
bids.append(OrderSummary(size=bid["size"], price=bid["price"]))
asks = []
for ask in raw_obs["asks"]:
asks.append(OrderSummary(size=ask["size"], price=ask["price"]))
orderbookSummary = OrderBookSummary(
market=raw_obs["market"],
asset_id=raw_obs["asset_id"],
timestamp=raw_obs["timestamp"],
last_trade_price=raw_obs["last_trade_price"],
min_order_size=raw_obs["min_order_size"],
neg_risk=raw_obs["neg_risk"],
tick_size=raw_obs["tick_size"],
bids=bids,
asks=asks,
hash=raw_obs["hash"],
)
return orderbookSummary
def generate_orderbook_summary_hash(orderbook: OrderBookSummary) -> str:
"""
Server-compatible orderbook hash.
The server computes SHA1 over a compact JSON payload with a specific key order,
and with the "hash" field set to an empty string while hashing.
"""
# Go server-side payload field order (struct order):
# market, asset_id, timestamp, hash, bids, asks, min_order_size, tick_size, neg_risk, last_trade_price
payload = {
"market": orderbook.market,
"asset_id": orderbook.asset_id,
"timestamp": orderbook.timestamp,
"hash": "",
"bids": [{"price": o.price, "size": o.size} for o in (orderbook.bids or [])],
"asks": [{"price": o.price, "size": o.size} for o in (orderbook.asks or [])],
"min_order_size": orderbook.min_order_size,
"tick_size": orderbook.tick_size,
"neg_risk": orderbook.neg_risk,
"last_trade_price": orderbook.last_trade_price,
}
serialized = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)
h = hashlib.sha1(serialized.encode("utf-8")).hexdigest()
orderbook.hash = h
return h
def order_to_json(order, owner, orderType, post_only: bool = False) -> dict:
return {"order": order.dict(), "owner": owner, "orderType": orderType, "postOnly": post_only}
def is_tick_size_smaller(a: TickSize, b: TickSize) -> bool:
return float(a) < float(b)
def price_valid(price: float, tick_size: TickSize) -> bool:
return price >= float(tick_size) and price <= 1 - float(tick_size)
================================================
FILE: requirements.txt
================================================
black==24.4.2
eth-account===0.13.0
eth-utils===4.1.1
poly_eip712_structs==0.0.1
py_order_utils==0.3.2
pytest==8.2.2
python-dotenv==0.19.2
websockets==12.0
py-builder-signing-sdk==0.0.2
httpx[http2]==0.27.0
================================================
FILE: setup.py
================================================
import setuptools
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setuptools.setup(
name="py_clob_client",
version="0.34.6",
author="Polymarket Engineering",
author_email="engineering@polymarket.com",
maintainer="Polymarket Engineering",
maintainer_email="engineering@polymarket.com",
description="Python client for the Polymarket CLOB",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/Polymarket/py-clob-client",
install_requires=[
"eth-account>=0.13.0",
"eth-utils>=4.1.1",
"poly_eip712_structs>=0.0.1",
"py-order-utils>=0.3.2",
"python-dotenv",
"py-builder-signing-sdk>=0.0.2",
"httpx[http2]>=0.27.0",
],
project_urls={
"Bug Tracker": "https://github.com/Polymarket/py-clob-client/issues",
},
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
packages=setuptools.find_packages(),
python_requires=">=3.9.10",
)
================================================
FILE: tests/__init__.py
================================================
================================================
FILE: tests/headers/__init__.py
================================================
================================================
FILE: tests/headers/test_headers.py
================================================
from datetime import datetime
from unittest import TestCase
from py_clob_client.clob_types import ApiCreds, RequestArgs
from py_clob_client.constants import AMOY
from py_clob_client.headers.headers import (
POLY_ADDRESS,
POLY_API_KEY,
POLY_NONCE,
POLY_PASSPHRASE,
POLY_SIGNATURE,
POLY_TIMESTAMP,
create_level_1_headers,
create_level_2_headers,
)
from py_clob_client.signer import Signer
# publicly known private key
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
creds = ApiCreds(
api_key="000000000-0000-0000-0000-000000000000",
api_passphrase="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
api_secret="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
)
class TestHeaders(TestCase):
def test_create_level_1_headers(self):
# no nonce
l1_headers = create_level_1_headers(signer)
self.assertIsNotNone(l1_headers)
self.assertEqual(l1_headers[POLY_ADDRESS], signer.address())
self.assertIsNotNone(l1_headers[POLY_SIGNATURE])
self.assertIsNotNone(l1_headers[POLY_TIMESTAMP])
self.assertTrue(
int(l1_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp())
)
self.assertEqual(l1_headers[POLY_NONCE], "0")
# nonce
l1_headers = create_level_1_headers(signer, nonce=1012)
self.assertIsNotNone(l1_headers)
self.assertEqual(l1_headers[POLY_ADDRESS], signer.address())
self.assertIsNotNone(l1_headers[POLY_SIGNATURE])
self.assertIsNotNone(l1_headers[POLY_TIMESTAMP])
self.assertTrue(
int(l1_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp())
)
self.assertEqual(l1_headers[POLY_NONCE], "1012")
def test_create_level_2_headers(self):
# no body
l2_headers = create_level_2_headers(
signer, creds, request_args=RequestArgs(method="get", request_path="/order")
)
self.assertIsNotNone(l2_headers)
self.assertEqual(l2_headers[POLY_ADDRESS], signer.address())
self.assertIsNotNone(l2_headers[POLY_SIGNATURE])
self.assertIsNotNone(l2_headers[POLY_TIMESTAMP])
self.assertTrue(
int(l2_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp())
)
self.assertEqual(l2_headers[POLY_API_KEY], creds.api_key)
self.assertEqual(l2_headers[POLY_PASSPHRASE], creds.api_passphrase)
# body
l2_headers = create_level_2_headers(
signer,
creds,
request_args=RequestArgs(
method="get", request_path="/order", body='{"hash": "0x123"}'
),
)
self.assertIsNotNone(l2_headers)
self.assertEqual(l2_headers[POLY_ADDRESS], signer.address())
self.assertIsNotNone(l2_headers[POLY_SIGNATURE])
self.assertIsNotNone(l2_headers[POLY_TIMESTAMP])
self.assertTrue(
int(l2_headers[POLY_TIMESTAMP]) <= int(datetime.now().timestamp())
)
self.assertEqual(l2_headers[POLY_API_KEY], creds.api_key)
self.assertEqual(l2_headers[POLY_PASSPHRASE], creds.api_passphrase)
================================================
FILE: tests/http_helpers/__init__.py
================================================
================================================
FILE: tests/http_helpers/test_helpers.py
================================================
from unittest import TestCase
from py_clob_client.clob_types import (
TradeParams,
OpenOrderParams,
DropNotificationParams,
BalanceAllowanceParams,
AssetType,
OrderScoringParams,
OrdersScoringParams,
)
from py_clob_client.http_helpers.helpers import (
build_query_params,
add_query_trade_params,
add_query_open_orders_params,
drop_notifications_query_params,
add_balance_allowance_params_to_url,
add_order_scoring_params_to_url,
add_orders_scoring_params_to_url,
)
class TestHelpers(TestCase):
def test_build_query_params(self):
# last is ?
url = build_query_params("http://tracker?", "q1", "a")
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?q1=a")
# last is not ?
url = build_query_params("http://tracker?q1=a", "q2", "b")
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?q1=a&q2=b")
def test_add_query_trade_params(self):
url = add_query_trade_params(
"http://tracker",
TradeParams(
market="10000",
after=1450000,
before=1460000,
asset_id="100",
maker_address="0x0",
id="aa-bb",
),
next_cursor="AA==",
)
self.assertIsNotNone(url)
self.assertEqual(
url,
"http://tracker?market=10000&asset_id=100&after=1450000&before=1460000&maker_address=0x0&id=aa-bb&next_cursor=AA==",
)
def test_add_query_trade_params_no_params_includes_next_cursor(self):
url = add_query_trade_params("http://tracker", None, next_cursor="AA==")
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?next_cursor=AA==")
def test_add_query_open_orders_params(self):
url = add_query_open_orders_params(
"http://tracker",
OpenOrderParams(market="10000", asset_id="100", id="aa-bb"),
)
self.assertIsNotNone(url)
self.assertEqual(
url,
"http://tracker?market=10000&asset_id=100&id=aa-bb&next_cursor=MA==",
)
def test_add_query_open_orders_params_no_params_includes_next_cursor(self):
url = add_query_open_orders_params("http://tracker", None, next_cursor="AA==")
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?next_cursor=AA==")
def test_drop_notifications_query_params(self):
url = drop_notifications_query_params(
"http://tracker",
DropNotificationParams(ids=["1", "2", "3"]),
)
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?ids=1,2,3")
def test_add_balance_allowance_params_to_url(self):
url = add_balance_allowance_params_to_url(
"http://tracker",
BalanceAllowanceParams(asset_type=AssetType.COLLATERAL, signature_type=0),
)
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?asset_type=COLLATERAL&signature_type=0")
url = add_balance_allowance_params_to_url(
"http://tracker",
BalanceAllowanceParams(
asset_type=AssetType.CONDITIONAL, token_id="222", signature_type=1
),
)
self.assertIsNotNone(url)
self.assertEqual(
url, "http://tracker?asset_type=CONDITIONAL&token_id=222&signature_type=1"
)
def test_add_order_scoring_params_to_url(self):
url = add_order_scoring_params_to_url(
"http://tracker",
OrderScoringParams(orderId="0x0123abc"),
)
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?order_id=0x0123abc")
def test_add_orders_scoring_params_to_urll(self):
url = add_orders_scoring_params_to_url(
"http://tracker",
OrdersScoringParams(orderIds=["0x0", "0x1", "0x2"]),
)
self.assertIsNotNone(url)
self.assertEqual(url, "http://tracker?order_ids=0x0,0x1,0x2")
================================================
FILE: tests/order_builder/__init__.py
================================================
================================================
FILE: tests/order_builder/test_builder.py
================================================
from unittest import TestCase
from py_clob_client.clob_types import (
OrderArgs,
MarketOrderArgs,
CreateOrderOptions,
OrderSummary,
OrderType,
)
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.signer import Signer
from py_clob_client.order_builder.builder import OrderBuilder, ROUNDING_CONFIG
from py_clob_client.order_builder.helpers import decimal_places, round_normal
from py_order_utils.model import (
POLY_GNOSIS_SAFE,
EOA,
BUY as UtilsBuy,
SELL as UtilsSell,
)
# publicly known private key
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
class TestOrderBuilder(TestCase):
def test_calculate_buy_market_price_FOK(self):
# empty
with self.assertRaises(Exception):
builder = OrderBuilder(signer)
builder.calculate_buy_market_price([], 100, OrderType.FOK)
# not enough
with self.assertRaises(Exception):
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="100"),
]
builder = OrderBuilder(signer)
builder.calculate_buy_market_price(positions, 100, OrderType.FOK)
# OK
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5
)
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="200"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.4
)
positions = [
OrderSummary(price="0.5", size="120"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5
)
positions = [
OrderSummary(price="0.5", size="200"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FOK), 0.5
)
def test_calculate_sell_market_price_FOK(self):
# empty
with self.assertRaises(Exception):
builder = OrderBuilder(signer)
builder.calculate_sell_market_price([], 100)
# not enough
with self.assertRaises(Exception):
positions = [
OrderSummary(price="0.4", size="10"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
builder.calculate_sell_market_price(positions, 100, OrderType.FOK)
# OK
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.5
)
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="300"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.4
)
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="200"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FOK), 0.4
)
positions = [
OrderSummary(price="0.3", size="300"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 200, OrderType.FOK), 0.4
)
positions = [
OrderSummary(price="0.3", size="334"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 300, OrderType.FOK), 0.3
)
def test_calculate_buy_market_price_FAK(self):
# empty
with self.assertRaises(Exception):
builder = OrderBuilder(signer)
builder.calculate_buy_market_price([], 100, OrderType.FAK)
# not enough
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5
)
# OK
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5
)
positions = [
OrderSummary(price="0.5", size="100"),
OrderSummary(price="0.4", size="200"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.4
)
positions = [
OrderSummary(price="0.5", size="120"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5
)
positions = [
OrderSummary(price="0.5", size="200"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.3", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_buy_market_price(positions, 100, OrderType.FAK), 0.5
)
def test_calculate_sell_market_price_FAK(self):
# empty
with self.assertRaises(Exception):
builder = OrderBuilder(signer)
builder.calculate_sell_market_price([], 100)
# not enough
positions = [
OrderSummary(price="0.4", size="10"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4
)
# OK
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.5
)
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="300"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4
)
positions = [
OrderSummary(price="0.3", size="100"),
OrderSummary(price="0.4", size="200"),
OrderSummary(price="0.5", size="10"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 100, OrderType.FAK), 0.4
)
positions = [
OrderSummary(price="0.3", size="300"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 200, OrderType.FAK), 0.4
)
positions = [
OrderSummary(price="0.3", size="334"),
OrderSummary(price="0.4", size="100"),
OrderSummary(price="0.5", size="100"),
]
builder = OrderBuilder(signer)
self.assertEqual(
builder.calculate_sell_market_price(positions, 300, OrderType.FAK), 0.3
)
def test_get_market_order_amounts_buy_0_1(self):
builder = OrderBuilder(signer)
delta_price = 0.1
delta_size = 0.01
amount = 0.01
while amount <= 1000:
price = 0.1
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
BUY, amount, price, ROUNDING_CONFIG["0.1"]
)
self.assertEqual(side, UtilsBuy)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 2), round_normal(price, 2)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_buy_0_01(self):
builder = OrderBuilder(signer)
delta_price = 0.01
delta_size = 0.01
amount = 0.01
while amount <= 100:
price = 0.01
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
BUY, amount, price, ROUNDING_CONFIG["0.01"]
)
self.assertEqual(side, UtilsBuy)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 4), round_normal(price, 4)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_buy_0_001(self):
builder = OrderBuilder(signer)
delta_price = 0.001
delta_size = 0.01
amount = 0.01
while amount <= 10:
price = 0.001
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
BUY, amount, price, ROUNDING_CONFIG["0.001"]
)
self.assertEqual(side, UtilsBuy)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 6), round_normal(price, 6)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_buy_0_0001(self):
builder = OrderBuilder(signer)
delta_price = 0.0001
delta_size = 0.01
amount = 0.01
while amount <= 1:
price = 0.0001
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
BUY, amount, price, ROUNDING_CONFIG["0.0001"]
)
self.assertEqual(side, UtilsBuy)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 8), round_normal(price, 8)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_sell_0_1(self):
builder = OrderBuilder(signer)
delta_price = 0.1
delta_size = 0.01
amount = 0.01
while amount <= 1000:
price = 0.1
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
SELL, amount, price, ROUNDING_CONFIG["0.1"]
)
self.assertEqual(side, UtilsSell)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 2), round_normal(price, 2)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_sell_0_01(self):
builder = OrderBuilder(signer)
delta_price = 0.01
delta_size = 0.01
amount = 0.01
while amount <= 100:
price = 0.01
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
SELL, amount, price, ROUNDING_CONFIG["0.01"]
)
self.assertEqual(side, UtilsSell)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 4), round_normal(price, 4)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_sell_0_001(self):
builder = OrderBuilder(signer)
delta_price = 0.001
delta_size = 0.01
amount = 0.01
while amount <= 10:
price = 0.001
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
SELL, amount, price, ROUNDING_CONFIG["0.001"]
)
self.assertEqual(side, UtilsSell)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 6), round_normal(price, 6)
)
price = price + delta_price
amount = amount + delta_size
def test_get_market_order_amounts_sell_0_0001(self):
builder = OrderBuilder(signer)
delta_price = 0.0001
delta_size = 0.01
amount = 0.01
while amount <= 1:
price = 0.0001
while price <= 1:
side, maker, taker = builder.get_market_order_amounts(
SELL, amount, price, ROUNDING_CONFIG["0.0001"]
)
self.assertEqual(side, UtilsSell)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(taker / maker, 8), round_normal(price, 8)
)
price = price + delta_price
amount = amount + delta_size
def test_get_order_amounts_buy_0_1(self):
builder = OrderBuilder(signer)
delta_price = 0.1
delta_size = 0.01
size = 0.01
while size <= 1000:
price = 0.1
while price <= 1:
side, maker, taker = builder.get_order_amounts(
BUY, size, price, ROUNDING_CONFIG["0.1"]
)
self.assertEqual(side, 0)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 2), round_normal(price, 2)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_buy_0_01(self):
builder = OrderBuilder(signer)
delta_price = 0.01
delta_size = 0.01
size = 0.01
while size <= 100:
price = 0.01
while price <= 1:
side, maker, taker = builder.get_order_amounts(
BUY, size, price, ROUNDING_CONFIG["0.01"]
)
self.assertEqual(side, 0)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 4), round_normal(price, 4)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_buy_0_001(self):
builder = OrderBuilder(signer)
delta_price = 0.001
delta_size = 0.01
size = 0.01
while size <= 10:
price = 0.001
while price <= 1:
side, maker, taker = builder.get_order_amounts(
BUY, size, price, ROUNDING_CONFIG["0.001"]
)
self.assertEqual(side, 0)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 6), round_normal(price, 6)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_buy_0_0001(self):
builder = OrderBuilder(signer)
delta_price = 0.0001
delta_size = 0.01
size = 0.01
while size <= 1:
price = 0.0001
while price <= 1:
side, maker, taker = builder.get_order_amounts(
BUY, size, price, ROUNDING_CONFIG["0.0001"]
)
self.assertEqual(side, 0)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(maker / taker, 8), round_normal(price, 8)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_sell_0_1(self):
builder = OrderBuilder(signer)
delta_price = 0.1
delta_size = 0.01
size = 0.01
while size <= 1000:
price = 0.1
while price <= 1:
side, maker, taker = builder.get_order_amounts(
SELL, size, price, ROUNDING_CONFIG["0.1"]
)
self.assertEqual(side, 1)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(taker / maker, 2), round_normal(price, 2)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_sell_0_01(self):
builder = OrderBuilder(signer)
delta_price = 0.01
delta_size = 0.01
size = 0.01
while size <= 100:
price = 0.01
while price <= 1:
side, maker, taker = builder.get_order_amounts(
SELL, size, price, ROUNDING_CONFIG["0.01"]
)
self.assertEqual(side, 1)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(taker / maker, 4), round_normal(price, 4)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_sell_0_001(self):
builder = OrderBuilder(signer)
delta_price = 0.001
delta_size = 0.01
size = 0.01
while size <= 10:
price = 0.001
while price <= 1:
side, maker, taker = builder.get_order_amounts(
SELL, size, price, ROUNDING_CONFIG["0.001"]
)
self.assertEqual(side, 1)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(taker / maker, 6), round_normal(price, 6)
)
price = price + delta_price
size = size + delta_size
def test_get_order_amounts_sell_0_0001(self):
builder = OrderBuilder(signer)
delta_price = 0.0001
delta_size = 0.01
size = 0.01
while size <= 1:
price = 0.0001
while price <= 1:
side, maker, taker = builder.get_order_amounts(
SELL, size, price, ROUNDING_CONFIG["0.0001"]
)
self.assertEqual(side, 1)
self.assertEqual(decimal_places(maker), 0)
self.assertEqual(decimal_places(taker), 0)
self.assertGreaterEqual(
round_normal(taker / maker, 8), round_normal(price, 8)
)
price = price + delta_price
size = size + delta_size
def test_create_order_decimal_accuracy(self):
builder = OrderBuilder(signer)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.24,
size=15,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
3600000,
)
self.assertEqual(
signed_order.order["takerAmount"],
15000000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.24,
size=15,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
15000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
3600000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.82,
size=101,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
82820000,
)
self.assertEqual(
signed_order.order["takerAmount"],
101000000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.82,
size=101,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
101000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
82820000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.78,
size=12.8205,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
9999600,
)
self.assertEqual(
signed_order.order["takerAmount"],
12820000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.78,
size=12.8205,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
12820000,
)
self.assertEqual(
signed_order.order["takerAmount"],
9999600,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.39,
size=2435.89,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
2435890000,
)
self.assertEqual(
signed_order.order["takerAmount"],
949997100,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.43,
size=19.1,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
19100000,
)
self.assertEqual(
signed_order.order["takerAmount"],
8213000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.58,
size=18233.33,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertEqual(
signed_order.order["makerAmount"],
10575331400,
)
self.assertEqual(
signed_order.order["takerAmount"],
18233330000,
)
self.assertEqual(
signed_order.order["makerAmount"] / signed_order.order["takerAmount"], 0.58
)
def test_create_order_buy_0_1(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.5,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
10520000,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.5,
)
def test_create_order_buy_0_01(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
11782400,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.56,
)
def test_create_order_buy_0_001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.056,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
1178240,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.056,
)
def test_create_order_buy_0_0001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.0056,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
117824,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.0056,
)
def test_create_order_sell_0_1(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.5,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
10520000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.5,
)
def test_create_order_sell_0_01(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
11782400,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.56,
)
def test_create_order_sell_0_001(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.056,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
1178240,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.056,
)
def test_create_order_sell_0_0001(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.0056,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
117824,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.0056,
)
def test_create_order_decimal_accuracy_neg_risk(self):
builder = OrderBuilder(signer)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.24,
size=15,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
3600000,
)
self.assertEqual(
signed_order.order["takerAmount"],
15000000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.24,
size=15,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
15000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
3600000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.82,
size=101,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
82820000,
)
self.assertEqual(
signed_order.order["takerAmount"],
101000000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.82,
size=101,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
101000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
82820000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.78,
size=12.8205,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
9999600,
)
self.assertEqual(
signed_order.order["takerAmount"],
12820000,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.78,
size=12.8205,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
12820000,
)
self.assertEqual(
signed_order.order["takerAmount"],
9999600,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.39,
size=2435.89,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
2435890000,
)
self.assertEqual(
signed_order.order["takerAmount"],
949997100,
)
# SELL
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.43,
size=19.1,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
19100000,
)
self.assertEqual(
signed_order.order["takerAmount"],
8213000,
)
# BUY
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.58,
size=18233.33,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertEqual(
signed_order.order["makerAmount"],
10575331400,
)
self.assertEqual(
signed_order.order["takerAmount"],
18233330000,
)
self.assertEqual(
signed_order.order["makerAmount"] / signed_order.order["takerAmount"], 0.58
)
def test_create_order_buy_0_1_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.5,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
10520000,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.5,
)
def test_create_order_buy_0_01_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
11782400,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.56,
)
def test_create_order_buy_0_001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.056,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
1178240,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.056,
)
def test_create_order_buy_0_0001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.0056,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
117824,
)
self.assertEqual(
signed_order.order["takerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.0056,
)
def test_create_order_sell_0_1_neg_risk(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.5,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
10520000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.5,
)
def test_create_order_sell_0_01_neg_risk(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
11782400,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.56,
)
def test_create_order_sell_0_001_neg_risk(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.056,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
1178240,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.056,
)
def test_create_order_sell_0_0001_neg_risk(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.0056,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
21040000,
)
self.assertEqual(
signed_order.order["takerAmount"],
117824,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
50000,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order.signature)
self.assertEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.0056,
)
def test_dict_order_buy_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertIsNotNone(signed_order)
signed_order_dict = signed_order.dict()
self.assertIsNotNone(signed_order_dict)
self.assertTrue(isinstance(signed_order_dict["salt"], int))
self.assertEqual(
signed_order_dict["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order_dict["tokenId"],
"123",
)
self.assertEqual(
signed_order_dict["makerAmount"],
"11782400",
)
self.assertEqual(
signed_order_dict["takerAmount"],
"21040000",
)
self.assertEqual(
signed_order_dict["side"],
BUY,
)
self.assertEqual(
signed_order_dict["expiration"],
"50000",
)
self.assertEqual(
signed_order_dict["nonce"],
"123",
)
self.assertEqual(
signed_order_dict["feeRateBps"],
"111",
)
self.assertEqual(
signed_order_dict["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order_dict["signature"])
def test_dict_order_sell_neg_risk(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertIsNotNone(signed_order)
signed_order_dict = signed_order.dict()
self.assertIsNotNone(signed_order_dict)
self.assertTrue(isinstance(signed_order_dict["salt"], int))
self.assertEqual(
signed_order_dict["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order_dict["tokenId"],
"123",
)
self.assertEqual(
signed_order_dict["makerAmount"],
"21040000",
)
self.assertEqual(
signed_order_dict["takerAmount"],
"11782400",
)
self.assertEqual(
signed_order_dict["side"],
SELL,
)
self.assertEqual(
signed_order_dict["expiration"],
"50000",
)
self.assertEqual(
signed_order_dict["nonce"],
"123",
)
self.assertEqual(
signed_order_dict["feeRateBps"],
"111",
)
self.assertEqual(
signed_order_dict["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order_dict["signature"])
def test_dict_order_buy(self):
builder = OrderBuilder(signer)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=BUY,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertIsNotNone(signed_order)
signed_order_dict = signed_order.dict()
self.assertIsNotNone(signed_order_dict)
self.assertTrue(isinstance(signed_order_dict["salt"], int))
self.assertEqual(
signed_order_dict["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order_dict["tokenId"],
"123",
)
self.assertEqual(
signed_order_dict["makerAmount"],
"11782400",
)
self.assertEqual(
signed_order_dict["takerAmount"],
"21040000",
)
self.assertEqual(
signed_order_dict["side"],
BUY,
)
self.assertEqual(
signed_order_dict["expiration"],
"50000",
)
self.assertEqual(
signed_order_dict["nonce"],
"123",
)
self.assertEqual(
signed_order_dict["feeRateBps"],
"111",
)
self.assertEqual(
signed_order_dict["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order_dict["signature"])
def test_dict_order_sell(self):
builder = OrderBuilder(signer, sig_type=POLY_GNOSIS_SAFE)
signed_order = builder.create_order(
order_args=OrderArgs(
token_id="123",
price=0.56,
size=21.04,
side=SELL,
fee_rate_bps=111,
nonce=123,
expiration=50000,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertIsNotNone(signed_order)
signed_order_dict = signed_order.dict()
self.assertIsNotNone(signed_order_dict)
self.assertTrue(isinstance(signed_order_dict["salt"], int))
self.assertEqual(
signed_order_dict["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order_dict["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order_dict["tokenId"],
"123",
)
self.assertEqual(
signed_order_dict["makerAmount"],
"21040000",
)
self.assertEqual(
signed_order_dict["takerAmount"],
"11782400",
)
self.assertEqual(
signed_order_dict["side"],
SELL,
)
self.assertEqual(
signed_order_dict["expiration"],
"50000",
)
self.assertEqual(
signed_order_dict["nonce"],
"123",
)
self.assertEqual(
signed_order_dict["feeRateBps"],
"111",
)
self.assertEqual(
signed_order_dict["signatureType"],
POLY_GNOSIS_SAFE,
)
self.assertIsNotNone(signed_order_dict["signature"])
def test_create_market_order_buy_0_1(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.5,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
200000000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.5,
)
def test_create_market_order_buy_0_01(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.56,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
178571400,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.56,
)
def test_create_market_order_buy_0_001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
1785714280,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.056,
)
def test_create_market_order_buy_0_0001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.0056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
17857142857,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.0056,
)
def test_create_market_order_buy_0_1_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.5,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
200000000,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.5,
)
def test_create_market_order_buy_0_01_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.56,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
178571400,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.56,
)
def test_create_market_order_buy_0_001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
1785714280,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.056,
)
def test_create_market_order_buy_0_0001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=BUY,
token_id="123",
price=0.0056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
17857142857,
)
self.assertEqual(
signed_order.order["side"],
0,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["makerAmount"])
/ float(signed_order.order["takerAmount"]),
0.0056,
)
def test_create_market_order_sell_0_1(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.5,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
50000000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.5,
)
def test_create_market_order_sell_0_01(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.56,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
56000000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.56,
)
def test_create_market_order_sell_0_001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
5600000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.056,
)
def test_create_market_order_sell_0_0001(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.0056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
560000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.0056,
)
def test_create_market_order_sell_0_1_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.5,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
50000000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.5,
)
def test_create_market_order_sell_0_01_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.56,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
56000000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.56,
)
def test_create_market_order_sell_0_001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
5600000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.056,
)
def test_create_market_order_sell_0_0001_neg_risk(self):
builder = OrderBuilder(signer)
signed_order = builder.create_market_order(
order_args=MarketOrderArgs(
side=SELL,
token_id="123",
price=0.0056,
amount=100,
fee_rate_bps=111,
nonce=123,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
)
self.assertTrue(isinstance(signed_order.order["salt"], int))
self.assertIsNotNone(signed_order)
self.assertEqual(
signed_order.order["maker"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["signer"],
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
)
self.assertEqual(
signed_order.order["taker"],
"0x0000000000000000000000000000000000000000",
)
self.assertEqual(
signed_order.order["tokenId"],
123,
)
self.assertEqual(
signed_order.order["makerAmount"],
100000000,
)
self.assertEqual(
signed_order.order["takerAmount"],
560000,
)
self.assertEqual(
signed_order.order["side"],
1,
)
self.assertEqual(
signed_order.order["expiration"],
0,
)
self.assertEqual(
signed_order.order["nonce"],
123,
)
self.assertEqual(
signed_order.order["feeRateBps"],
111,
)
self.assertEqual(
signed_order.order["signatureType"],
EOA,
)
self.assertIsNotNone(signed_order.signature)
self.assertGreaterEqual(
float(signed_order.order["takerAmount"])
/ float(signed_order.order["makerAmount"]),
0.0056,
)
================================================
FILE: tests/order_builder/test_helpers.py
================================================
from unittest import TestCase
from py_clob_client.order_builder.helpers import decimal_places
class TestHelpers(TestCase):
def test_decimal_places(self):
self.assertEqual(decimal_places(949.9970999999999), 13)
self.assertEqual(decimal_places(949), 0)
================================================
FILE: tests/rfq/test_rfq_payload.py
================================================
from unittest import TestCase
from py_clob_client.rfq.rfq_client import RfqClient
from py_clob_client.rfq.rfq_types import MatchType
from py_clob_client.order_builder.constants import BUY, SELL
class TestCreateAcceptQuotePayload(TestCase):
def test_complementary(self):
client = RfqClient(parent=None)
quote = {
"matchType": "COMPLEMENTARY",
"side": BUY,
"token": "tokenA",
"sizeIn": "100",
"sizeOut": "50",
"price": "0.5",
}
payload = client._get_request_order_creation_payload(quote)
self.assertEqual(payload["token"], "tokenA")
self.assertEqual(payload["side"], SELL)
self.assertEqual(payload["size"], "100")
self.assertEqual(payload["price"], 0.5)
quote = {
"matchType": "COMPLEMENTARY",
"side": SELL,
"token": "tokenB",
"sizeIn": "200",
"sizeOut": "75",
"price": "0.60"
}
payload = client._get_request_order_creation_payload(quote)
self.assertEqual(payload["token"], "tokenB")
self.assertEqual(payload["side"], BUY)
self.assertEqual(payload["size"], "75")
self.assertEqual(payload["price"], 0.60)
def test_mint_merge(self):
client = RfqClient(parent=None)
quote = {
"matchType": "MERGE",
"side": BUY,
"complement": "tokenC",
"sizeIn": "30",
"sizeOut": "15",
"price": "0.35",
}
payload = client._get_request_order_creation_payload(quote)
self.assertEqual(payload["token"], "tokenC")
self.assertEqual(payload["side"], BUY)
self.assertEqual(payload["size"], "30")
self.assertEqual(payload["price"], 0.65)
quote = {
"matchType": "MINT",
"side": BUY,
"complement": "tokenC",
"sizeIn": "30", # tokens bought
"sizeOut": "15",
"price": "0.40",
}
payload = client._get_request_order_creation_payload(quote)
self.assertEqual(payload["token"], "tokenC")
self.assertEqual(payload["side"], BUY)
self.assertEqual(payload["size"], "30")
self.assertEqual(payload["price"], 0.60)
================================================
FILE: tests/rfq/test_rfq_query_params.py
================================================
from unittest import TestCase
from urllib.parse import urlencode
from py_clob_client.rfq import GetRfqRequestsParams, GetRfqQuotesParams
from py_clob_client.rfq.rfq_helpers import (
parse_rfq_requests_params,
parse_rfq_quotes_params,
)
class TestRfqQueryParams(TestCase):
def test_get_rfq_requests_request_ids_are_repeated_query_params(self):
id1 = "019b69d4-2eb6-7ef9-8595-d149c97de10b"
id2 = "019b69c3-d49e-7abf-88d0-cb3fd79fb721"
params = GetRfqRequestsParams(request_ids=[id1, id2])
parsed = parse_rfq_requests_params(params)
qs = urlencode(parsed, doseq=True)
self.assertEqual(qs, f"requestIds={id1}&requestIds={id2}")
def test_get_rfq_quotes_quote_ids_are_repeated_query_params(self):
q1 = "019b69d4-2eb6-7ef9-8595-d149c97de10b"
q2 = "019b69c3-d49e-7abf-88d0-cb3fd79fb721"
params = GetRfqQuotesParams(quote_ids=[q1, q2])
parsed = parse_rfq_quotes_params(params)
qs = urlencode(parsed, doseq=True)
self.assertEqual(qs, f"quoteIds={q1}"eIds={q2}")
================================================
FILE: tests/signing/__init__.py
================================================
================================================
FILE: tests/signing/test_eip712.py
================================================
from unittest import TestCase
from py_clob_client.constants import AMOY
from py_clob_client.signer import Signer
from py_clob_client.signing.eip712 import sign_clob_auth_message
# publicly known private key
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
class TestEIP712(TestCase):
def test_sign_clob_auth_message(self):
signature = sign_clob_auth_message(signer, 10000000, 23)
self.assertIsNotNone(signature)
self.assertEqual(
signature,
"0xf62319a987514da40e57e2f4d7529f7bac38f0355bd88bb5adbb3768d80de6c1682518e0af677d5260366425f4361e7b70c25ae232aff0ab2331e2b164a1aedc1b",
)
================================================
FILE: tests/signing/test_hmac.py
================================================
from unittest import TestCase
import binascii
from py_clob_client.signing.hmac import build_hmac_signature
class TestHMAC(TestCase):
def setUp(self):
# Baseline inputs used across variation tests
self.secret = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
self.timestamp = "1000000"
self.method = "test-sign"
self.path = "/orders"
self.string_body = '{"hash": "0x123"}'
self.baseline_signature = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, self.string_body
)
def test_build_hmac_signature_matches_expected(self):
signature = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, self.string_body
)
self.assertIsNotNone(signature)
# Expected signature for current implementation (no method mutation, verbatim string body)
self.assertEqual("ZwAdJKvoYRlEKDkNMwd5BuwNNtg93kNaR_oU2HrfVvc=", signature)
def test_dict_body_same_as_equivalent_string_body(self):
# Current hmac implementation converts dict to python str() then swaps single to double quotes.
# For a simple dict this matches the provided JSON string exactly, so signatures should be equal.
dict_body_sig = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"}
)
self.assertEqual(self.baseline_signature, dict_body_sig)
def test_different_method_changes_signature(self):
get_sig = build_hmac_signature(
self.secret, self.timestamp, "GET", self.path, {"hash": "0x123"}
)
post_sig = build_hmac_signature(
self.secret, self.timestamp, "POST", self.path, {"hash": "0x123"}
)
self.assertNotEqual(get_sig, post_sig)
self.assertNotEqual(get_sig, self.baseline_signature)
def test_different_timestamp_changes_signature(self):
sig_new_time = build_hmac_signature(
self.secret, "1000001", self.method, self.path, {"hash": "0x123"}
)
self.assertNotEqual(sig_new_time, self.baseline_signature)
def test_different_path_changes_signature(self):
sig_path = build_hmac_signature(
self.secret,
self.timestamp,
self.method,
"/api/v1/orders",
{"hash": "0x123"},
)
self.assertNotEqual(sig_path, self.baseline_signature)
def test_extra_key_and_ordering_affect_signature(self):
sig_order1 = build_hmac_signature(
self.secret,
self.timestamp,
self.method,
self.path,
{"hash": "0x123", "foo": "bar"},
)
sig_order2 = build_hmac_signature(
self.secret,
self.timestamp,
self.method,
self.path,
{"foo": "bar", "hash": "0x123"},
)
self.assertNotEqual(sig_order1, sig_order2)
self.assertNotEqual(sig_order1, self.baseline_signature)
def test_array_body_signature(self):
sig_array = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, [1, 2, 3]
)
self.assertIsNotNone(sig_array)
self.assertNotEqual(sig_array, self.baseline_signature)
def test_unicode_body_signature(self):
sig_unicode = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, {"emoji": "😃"}
)
self.assertIsNotNone(sig_unicode)
self.assertNotEqual(sig_unicode, self.baseline_signature)
def test_none_body_omitted_from_message(self):
sig_none = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, None
)
self.assertNotEqual(sig_none, self.baseline_signature)
def test_empty_string_body_omitted(self):
sig_empty = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, ""
)
self.assertNotEqual(sig_empty, self.baseline_signature)
def test_none_and_empty_body_same_signature(self):
sig_none = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, None
)
sig_empty = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, ""
)
self.assertEqual(sig_none, sig_empty)
def test_idempotent_same_inputs(self):
sig1 = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"}
)
sig2 = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"}
)
self.assertEqual(sig1, sig2)
def test_different_secret_changes_signature(self):
other_secret = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="
sig_other = build_hmac_signature(
other_secret, self.timestamp, self.method, self.path, {"hash": "0x123"}
)
sig_original = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, {"hash": "0x123"}
)
self.assertNotEqual(sig_other, sig_original)
def test_invalid_secret_raises(self):
with self.assertRaises(binascii.Error):
build_hmac_signature(
"!!!notbase64!!!",
self.timestamp,
self.method,
self.path,
{"hash": "0x123"},
)
def test_boolean_body_signature(self):
sig_true = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, True
)
sig_false = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, False
)
self.assertIsNotNone(sig_true)
self.assertIsNotNone(sig_false)
self.assertNotEqual(sig_true, sig_false)
def test_numeric_body_signature(self):
sig_int = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, 42
)
sig_float = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, 3.14159
)
self.assertIsNotNone(sig_int)
self.assertIsNotNone(sig_float)
self.assertNotEqual(sig_int, sig_float)
def test_nested_object_no_sorting_means_signatures_can_differ(self):
body_a = {"a": {"z": 1, "b": 2}, "c": [3, 2, 1]}
body_b = {"c": [3, 2, 1], "a": {"b": 2, "z": 1}}
sig_a = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, body_a
)
sig_b = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, body_b
)
self.assertNotEqual(sig_a, sig_b)
def test_list_of_dicts_key_order_affects_signature(self):
body1 = [{"b": 2, "a": 1}, {"d": 4, "c": 3}]
body2 = [{"a": 1, "b": 2}, {"c": 3, "d": 4}]
sig1 = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, body1
)
sig2 = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, body2
)
self.assertNotEqual(sig1, sig2)
def test_string_body_preserved_verbatim(self):
string_a = '{"x":1, "y":2}'
string_b = '{"x":1,"y":2}'
sig_a = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, string_a
)
sig_b = build_hmac_signature(
self.secret, self.timestamp, self.method, self.path, string_b
)
self.assertNotEqual(sig_a, sig_b)
================================================
FILE: tests/test_utilities.py
================================================
from unittest import TestCase
from py_clob_client.clob_types import (
OrderArgs,
OrderType,
CreateOrderOptions,
)
from py_clob_client.constants import AMOY
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.signer import Signer
from py_clob_client.order_builder.builder import OrderBuilder
from py_clob_client.utilities import (
parse_raw_orderbook_summary,
generate_orderbook_summary_hash,
order_to_json,
is_tick_size_smaller,
price_valid,
)
class TestUtilities(TestCase):
def test_parse_raw_orderbook_summary(self):
raw_obs = {
"market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"bids": [
{"price": "0.15", "size": "100"},
{"price": "0.31", "size": "148.56"},
{"price": "0.33", "size": "58"},
{"price": "0.5", "size": "100"},
],
"asks": [],
"hash": "9d6d9e8831a150ac4cd878f99f7b2c6d419b875f",
"min_order_size": "100",
"neg_risk": False,
"tick_size": "0.01",
"timestamp": "123456789",
"last_trade_price": "",
}
orderbook_summary = parse_raw_orderbook_summary(raw_obs)
self.assertEqual(
orderbook_summary.market,
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
)
self.assertEqual(
orderbook_summary.asset_id,
"52114319501245915516055106046884209969926127482827954674443846427813813222426",
)
self.assertEqual(
orderbook_summary.hash, "9d6d9e8831a150ac4cd878f99f7b2c6d419b875f"
)
self.assertEqual(orderbook_summary.timestamp, "123456789")
self.assertEqual(orderbook_summary.min_order_size, "100")
self.assertEqual(orderbook_summary.neg_risk, False)
self.assertEqual(orderbook_summary.tick_size, "0.01")
self.assertIsNotNone(orderbook_summary.asks)
self.assertIsNotNone(orderbook_summary.bids)
self.assertEqual(len(orderbook_summary.asks), 0)
self.assertEqual(len(orderbook_summary.bids), 4)
self.assertEqual(orderbook_summary.bids[0].price, "0.15")
self.assertEqual(orderbook_summary.bids[0].size, "100")
self.assertEqual(orderbook_summary.bids[1].price, "0.31")
self.assertEqual(orderbook_summary.bids[1].size, "148.56")
self.assertEqual(orderbook_summary.bids[2].price, "0.33")
self.assertEqual(orderbook_summary.bids[2].size, "58")
self.assertEqual(orderbook_summary.bids[3].price, "0.5")
self.assertEqual(orderbook_summary.bids[3].size, "100")
raw_obs = {
"market": "0xaabbcc",
"asset_id": "100",
"bids": [],
"asks": [],
"hash": "7f81a35a09e1933a96b05edb51ac4be4a6163146",
"timestamp": "123456789",
"min_order_size": "100",
"neg_risk": False,
"tick_size": "0.01",
"last_trade_price": "",
}
orderbook_summary = parse_raw_orderbook_summary(raw_obs)
self.assertEqual(
orderbook_summary.market,
"0xaabbcc",
)
self.assertEqual(
orderbook_summary.asset_id,
"100",
)
self.assertEqual(orderbook_summary.min_order_size, "100")
self.assertEqual(orderbook_summary.neg_risk, False)
self.assertEqual(orderbook_summary.tick_size, "0.01")
self.assertEqual(
orderbook_summary.hash, "7f81a35a09e1933a96b05edb51ac4be4a6163146"
)
self.assertEqual(orderbook_summary.timestamp, "123456789")
self.assertIsNotNone(orderbook_summary.asks)
self.assertIsNotNone(orderbook_summary.bids)
self.assertEqual(len(orderbook_summary.asks), 0)
self.assertEqual(len(orderbook_summary.bids), 0)
def test_generate_orderbook_summary_hash(self):
raw_obs = {
"market": "0xaabbcc",
"asset_id": "100",
"bids": [
{"price": "0.3", "size": "100"},
{"price": "0.4", "size": "100"},
],
"asks": [
{"price": "0.6", "size": "100"},
{"price": "0.7", "size": "100"},
],
"hash": "",
"timestamp": "123456789",
"min_order_size": "100",
"neg_risk": False,
"tick_size": "0.01",
"last_trade_price": "0.5",
}
orderbook_summary = parse_raw_orderbook_summary(raw_obs)
self.assertEqual(
generate_orderbook_summary_hash(orderbook_summary),
"0458ea5755c9f73d64a14636fa5c36ed460ec394",
)
self.assertEqual(
orderbook_summary.hash,
"0458ea5755c9f73d64a14636fa5c36ed460ec394",
)
raw_obs = {
"market": "0xaabbcc",
"asset_id": "100",
"timestamp": "123456789",
"bids": [
{"price": "0.3", "size": "100"},
{"price": "0.4", "size": "100"},
],
"asks": [
{"price": "0.6", "size": "100"},
{"price": "0.7", "size": "100"},
],
"min_order_size": "100",
"neg_risk": False,
"tick_size": "0.01",
"last_trade_price": "0.5",
"hash": "",
}
orderbook_summary = parse_raw_orderbook_summary(raw_obs)
self.assertEqual(
generate_orderbook_summary_hash(orderbook_summary),
"0458ea5755c9f73d64a14636fa5c36ed460ec394",
)
self.assertEqual(
orderbook_summary.hash,
"0458ea5755c9f73d64a14636fa5c36ed460ec394",
)
raw_obs = {
"market": "0xaabbcc",
"asset_id": "100",
"timestamp": "",
"bids": [],
"asks": [],
"hash": "",
"min_order_size": "100",
"neg_risk": False,
"tick_size": "0.01",
"last_trade_price": "0.5",
}
orderbook_summary = parse_raw_orderbook_summary(raw_obs)
self.assertEqual(
generate_orderbook_summary_hash(orderbook_summary),
"74c6a7c81c1d572f1c877b7d3e25b80c336d8a6e",
)
self.assertEqual(
orderbook_summary.hash,
"74c6a7c81c1d572f1c877b7d3e25b80c336d8a6e",
)
def test_order_to_json_0_1(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
post_only=True,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["postOnly"], True)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_01(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "5000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "5000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "5000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "5000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_001(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "500000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "500000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "500000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "500000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_0001(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=False),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_1_neg_risk(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.5,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.1", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_01_neg_risk(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "5000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "5000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "5000000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.05,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.01", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "5000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_001_neg_risk(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "500000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "500000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "500000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "500000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_order_to_json_0_0001_neg_risk(self):
# publicly known private key
private_key = (
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
chain_id = AMOY
signer = Signer(private_key=private_key, chain_id=chain_id)
owner = "aaa-bbb-ccc"
builder = OrderBuilder(signer)
# GTC BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTC SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTC,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTC")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD BUY
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=BUY,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "50000")
self.assertEqual(json_order["order"]["takerAmount"], "100000000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "BUY")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
# GTD SELL
json_order = order_to_json(
order=builder.create_order(
order_args=OrderArgs(
token_id="100",
price=0.0005,
size=100,
side=SELL,
),
options=CreateOrderOptions(tick_size="0.0001", neg_risk=True),
),
owner=owner,
orderType=OrderType.GTD,
)
self.assertIsNotNone(json_order)
self.assertEqual(json_order["orderType"], "GTD")
self.assertEqual(json_order["owner"], owner)
self.assertIsNotNone(json_order["order"])
self.assertIsNotNone(json_order["order"]["salt"])
self.assertEqual(
json_order["order"]["maker"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["signer"], "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
self.assertEqual(
json_order["order"]["taker"], "0x0000000000000000000000000000000000000000"
)
self.assertEqual(json_order["order"]["tokenId"], "100")
self.assertEqual(json_order["order"]["makerAmount"], "100000000")
self.assertEqual(json_order["order"]["takerAmount"], "50000")
self.assertEqual(json_order["order"]["expiration"], "0")
self.assertEqual(json_order["order"]["nonce"], "0")
self.assertEqual(json_order["order"]["feeRateBps"], "0")
self.assertEqual(json_order["order"]["side"], "SELL")
self.assertEqual(json_order["order"]["signatureType"], 0)
self.assertIsNotNone(json_order["order"]["signature"])
def test_is_tick_size_smaller(self):
# 0.1
self.assertFalse(is_tick_size_smaller("0.1", "0.1"))
self.assertFalse(is_tick_size_smaller("0.1", "0.01"))
self.assertFalse(is_tick_size_smaller("0.1", "0.001"))
self.assertFalse(is_tick_size_smaller("0.1", "0.0001"))
# 0.01
self.assertTrue(is_tick_size_smaller("0.01", "0.1"))
self.assertFalse(is_tick_size_smaller("0.01", "0.01"))
self.assertFalse(is_tick_size_smaller("0.01", "0.001"))
self.assertFalse(is_tick_size_smaller("0.01", "0.0001"))
# 0.001
self.assertTrue(is_tick_size_smaller("0.001", "0.1"))
self.assertTrue(is_tick_size_smaller("0.001", "0.01"))
self.assertFalse(is_tick_size_smaller("0.001", "0.001"))
self.assertFalse(is_tick_size_smaller("0.001", "0.0001"))
# 0.0001
self.assertTrue(is_tick_size_smaller("0.0001", "0.1"))
self.assertTrue(is_tick_size_smaller("0.0001", "0.01"))
self.assertTrue(is_tick_size_smaller("0.0001", "0.001"))
self.assertFalse(is_tick_size_smaller("0.0001", "0.0001"))
def test_price_valid(self):
self.assertFalse(price_valid(0.00001, "0.0001"))
self.assertTrue(price_valid(0.0001, "0.0001"))
self.assertTrue(price_valid(0.001, "0.0001"))
self.assertTrue(price_valid(0.01, "0.0001"))
self.assertTrue(price_valid(0.1, "0.0001"))
self.assertTrue(price_valid(0.9, "0.0001"))
self.assertTrue(price_valid(0.99, "0.0001"))
self.assertTrue(price_valid(0.999, "0.0001"))
self.assertTrue(price_valid(0.9999, "0.0001"))
self.assertFalse(price_valid(0.99999, "0.0001"))
self.assertFalse(price_valid(0.00001, "0.001"))
self.assertFalse(price_valid(0.0001, "0.001"))
self.assertTrue(price_valid(0.001, "0.001"))
self.assertTrue(price_valid(0.01, "0.001"))
self.assertTrue(price_valid(0.1, "0.001"))
self.assertTrue(price_valid(0.9, "0.001"))
self.assertTrue(price_valid(0.99, "0.001"))
self.assertTrue(price_valid(0.999, "0.001"))
self.assertFalse(price_valid(0.9999, "0.001"))
self.assertFalse(price_valid(0.99999, "0.001"))
self.assertFalse(price_valid(0.00001, "0.01"))
self.assertFalse(price_valid(0.0001, "0.01"))
self.assertFalse(price_valid(0.001, "0.01"))
self.assertTrue(price_valid(0.01, "0.01"))
self.assertTrue(price_valid(0.1, "0.01"))
self.assertTrue(price_valid(0.9, "0.01"))
self.assertTrue(price_valid(0.99, "0.01"))
self.assertFalse(price_valid(0.999, "0.01"))
self.assertFalse(price_valid(0.9999, "0.01"))
self.assertFalse(price_valid(0.99999, "0.01"))
self.assertFalse(price_valid(0.00001, "0.1"))
self.assertFalse(price_valid(0.0001, "0.1"))
self.assertFalse(price_valid(0.001, "0.1"))
self.assertFalse(price_valid(0.01, "0.1"))
self.assertTrue(price_valid(0.1, "0.1"))
self.assertTrue(price_valid(0.9, "0.1"))
self.assertFalse(price_valid(0.99, "0.1"))
self.assertFalse(price_valid(0.999, "0.1"))
self.assertFalse(price_valid(0.9999, "0.1"))
self.assertFalse(price_valid(0.99999, "0.1"))