Crypto
The integration with crypto exchanges is done by using the CCXT package. It provides both market data as well as broker functionality from these exchanges.
Supported Exchanges¶
CCXT supports 100+ exchanges. Some popular ones include:
| Exchange | Class |
|---|---|
| Binance | ccxt.binance() |
| Coinbase | ccxt.coinbase() |
| Kraken | ccxt.kraken() |
| Bybit | ccxt.bybit() |
| OKX | ccxt.okx() |
import ccxt
# List first 10 exchanges
print(ccxt.exchanges[:10])['alpaca', 'apex', 'aster', 'backpack', 'bequant', 'bigone', 'binance', 'binancecoinm', 'binanceus', 'binanceusdm']
Market Data¶
CCXT provides access to historical OHLCV data, order books, and live ticker feeds from hundreds of cryptocurrency exchanges.
The following example shows a back test over historical data gotten from Binance exchange. This uses a public API, so no trading account with Binance is required for this example.
import ccxt
import roboquant as rq
from roboquant.feeds.crypto import CryptoFeed
from roboquant.common.monetary import USDT
rq.set_light_style()
exchange = ccxt.binance()
# exchange = ccxt.kraken() # or any other exchange supported by ccxt
feed = CryptoFeed(exchange, "BTC/USDT", "ETH/USDT", start_date="2020-01-01 00:00:00", interval="1d")
strategy = rq.strategies.EMACrossover()
trader = rq.traders.FlexTrader(size_fractions=4, max_order_pct=0.2, max_position_pct=0.5, shorting=True)
broker = rq.brokers.SimBroker(deposit=10_000@USDT)
account = rq.run(feed, strategy, trader=trader, broker=broker)
print(account)
for asset in feed.assets():
feed.plot(asset, trades=account.trades)ERROR:roboquant.feeds.crypto:Error retrieving symbol=BTC/USDT
Traceback (most recent call last):
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 687, in fetch
response.raise_for_status()
File "/home/runner/work/_temp/setup-uv-cache/archive-v0/JZUQWwThcZ-Yrkeu/lib/python3.12/site-packages/requests/models.py", line 1167, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 451 Client Error: for url: https://api.binance.com/api/v3/exchangeInfo
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/runner/work/roboquant.py/roboquant.py/roboquant/feeds/crypto.py", line 52, in __init__
rows: list[list[Any]] = exchange.fetch_ohlcv(
^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 4709, in fetch_ohlcv
self.load_markets()
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 1839, in load_markets
markets = self.fetch_markets(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 3241, in fetch_markets
promisesRaw.append(self.publicGetExchangeInfo(params))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/types.py", line 35, in unbound_method
return _self.request(self.path, self.api, self.method, params, config=self.config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 11819, in request
response = self.fetch2(path, api, method, params, headers, body, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 5562, in fetch2
raise e
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 5545, in fetch2
response = self.fetch(request['url'], request['method'], request['headers'], request['body'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 705, in fetch
self.handle_http_status_code(http_status_code, http_status_text, url, method, http_response)
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 2015, in handle_http_status_code
raise ErrorClass(self.id + ' ' + method + ' ' + url + ' ' + codeAsString + ' ' + reason + ' ' + body)
ccxt.base.errors.ExchangeNotAvailable: binance GET https://api.binance.com/api/v3/exchangeInfo 451 {
"code": 0,
"msg": "Service unavailable from a restricted location according to 'b. Eligibility' in https://www.binance.com/en/terms. Please contact customer service if you believe you received this message in error."
}
ERROR:roboquant.feeds.crypto:Error retrieving symbol=ETH/USDT
Traceback (most recent call last):
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 687, in fetch
response.raise_for_status()
File "/home/runner/work/_temp/setup-uv-cache/archive-v0/JZUQWwThcZ-Yrkeu/lib/python3.12/site-packages/requests/models.py", line 1167, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 451 Client Error: for url: https://api.binance.com/api/v3/exchangeInfo
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/runner/work/roboquant.py/roboquant.py/roboquant/feeds/crypto.py", line 52, in __init__
rows: list[list[Any]] = exchange.fetch_ohlcv(
^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 4709, in fetch_ohlcv
self.load_markets()
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 1839, in load_markets
markets = self.fetch_markets(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 3241, in fetch_markets
promisesRaw.append(self.publicGetExchangeInfo(params))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/types.py", line 35, in unbound_method
return _self.request(self.path, self.api, self.method, params, config=self.config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/binance.py", line 11819, in request
response = self.fetch2(path, api, method, params, headers, body, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 5562, in fetch2
raise e
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 5545, in fetch2
response = self.fetch(request['url'], request['method'], request['headers'], request['body'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 705, in fetch
self.handle_http_status_code(http_status_code, http_status_text, url, method, http_response)
File "/home/runner/work/roboquant.py/roboquant.py/.venv/lib/python3.12/site-packages/ccxt/base/exchange.py", line 2015, in handle_http_status_code
raise ErrorClass(self.id + ' ' + method + ' ' + url + ' ' + codeAsString + ' ' + reason + ' ' + body)
ccxt.base.errors.ExchangeNotAvailable: binance GET https://api.binance.com/api/v3/exchangeInfo 451 {
"code": 0,
"msg": "Service unavailable from a restricted location according to 'b. Eligibility' in https://www.binance.com/en/terms. Please contact customer service if you believe you received this message in error."
}
buying power : 10,000@USDT
cash : 10,000@USDT
equity : 10,000@USDT
positions : none
trades : 0
mkt value : 0@USDT
orders : none
last update : 1900-01-01 00:00:00+00:00
Broker Integration¶
For broker integration you typically need a trading account with the Exchange/Broker you want to use.
from dotenv import load_env
load_env()
key = os.getenv("ALPACA_API_KEY")
secret = os.getenv("ALPACA_SECRET")
assert(key is not None and secret is not None), "ALPACA_API_KEY and ALPACA_SECRET must be set"
alpaca = ccxt.alpaca({
"apiKey": key,
"secret": secret
})
alpaca.set_sandbox_mode(True)
broker = CryptoBroker(alpaca)
account = broker.sync()