Anyone use backtrader to do live trading on Bitcoin exchange?
-
@thatblokedave
Definitively coming to the same conclusion and probably the same solution or a solution using a smart ratelimiter.
But If we don't need those broker values intensively, we can cheat.You can check my thought here : https://github.com/bartosh/backtrader/issues/22
Even for getposition(). A strategy can store and update his own size with orders notifications.
-
Hi everyone,
First of all thanks @Ed-Bartosh for implementing the CCXT broker.
I was wandering what is the official repo for this and if there is any plan to contribute this back to backtrader or to develop as a standalone module that people could use.
I'm starting to use it, and I'd be happy to contribute to it but so far the only thing I have found is this fork: https://github.com/bartosh/backtrader/tree/ccxt
Thanks
Simone -
I think the most up to date repo is this one:
https://github.com/Dave-Vallance/bt-ccxt-store -
Thanks @sandro-böhme , the repo that you mention seems to be the latest one and is working fine with Binance as per my testings. I have a question in regards to the order status. I do place orders correctly and can see the order status in the dashboard. However, in the notify_order() when it comes to printing exections details like :
self.log (order.executed.price,order.executed.value,order.executed.comm)It always prints 0 for all 3 values, I am not sure why I cant see the order execution details. Does it work for you? Also, is there anyone actively looking at fixing the reported issues?
Thanks
-
Hey, Im having a problem when trying to run the following code.
I get the error: AttributeError: module 'backtrader.feeds' has no attribute 'CCXT'
I'm running the latest version of python on the latest version of ubuntu and when I check pip3 freeze, I have backtrader and ccxt installed.import backtrader as bt
import ccxt
import pandas as pdclass Strategy():
def init(self, client, timeframe='5m'):
self.client = client
self.timeframe = timeframedef getSignal(self): cerebro = bt.Cerebro() data = bt.feeds.CCXT(exchange='bitmex', symbol='BTC/USD', timeframe=bt.TimeFrame.Minutes, compression=1) cerebro.addstrategy(bt.Strategy) cerebro.adddata(data) print(data) cerebro.run() cerebro.plot(style="candlesticks")
any help would be appreciated
-
@noh I did have a similar issue which resolved it. You need to make sure to create a new environment with correct version of the BT fork for CCXT. See below the steps I followed to fix my issue:
conda create --name New-env
source activate New-env
conda install -c anaconda git
pip install ccxt
pip install git+https://github.com/Dave-Vallance/bt-ccxt-store.gitThis should resolve your issue.
-
I published a simple example with Binance integration: https://github.com/rodrigo-brito/backtrader-binance-bot
-
@rodrigo-brito This looks great thanks for sharing!
-
@rodrigo-brito
how do you achieve data persistence between restarts? -
@coolernax I don't persist the feed or strategies positions. The feed loads a delayed history when started. About the trade position, I'm start always with no funds in crypto, the first operation should be a buy. Maybe it can be improved with a simple flag in the script.
-
- When running your script in live mode does the notify_order() return correct order details? when i place order I am unable to get filled price back from order.executed.price,order.executed.value,order.executed.comm all the fileds returning 0. Is this something that anyone looking at fixing?
- How stable do you think the CCXT Live broker for BT is at the moment? Do you have high confidence in it's stability? Are you running it live?
- Also, the Dave-wallace fork seems to have a new function self.getposition() whch does not seem to work for Binance as i receive empty object where I should get a list of my open positions.
-
Hi, @pfederra
- I have the same issue in
notify_order()
, it works only in simulations to me. - I think the fork has a lot of issues, but work very well for the main features, like order and feed.
- The get positions does not work for me very well, it has a precision issue. I'm using a function to get my wallet ballance and settting a custom sizer. I'm also defining a global variable with the last operation (BUY/SELL) to control the next operation. It is a working arrond, but working in live.
- I have the same issue in
-
@rodrigo-brito
How do we proceed to test with another dataset ? (ex: from 01/01/2019 to 05/05/2019)
It seems that your scripts do not incorporate params to generate a csv file with from some date to another.Best regards,
Diamond -
Hi there. In each loop (calling _load()), maybe more than one trade is appended in the "for trade in trades" block, but only one trade is popped, ie. trade = self.trades.popleft(). Will this cause delay? Will this datafeed be much slower than the real world?
-
Hi guys. I am using this CCXTbt library, and to be honnest, it's kinda hard getting it to work properly. I have a simple question: How ot have a fetch_ohlcv function work on an optimised time frame ? The thing is, I see this function running all the time, spamming the exchange with no reason. I think that instead, it should be called at a fixed time, like every minute, or every granularity, more generally speaking.
I am perfectly aware of the rateLimit parameter on the exchange, but I don't want to set a timeout between my API calls: I don't want any timeout between the time I fetch a ticker, and place an order, because a small wait can result in losing a bid or a sell.
-
@theroque said in Anyone use backtrader to do live trading on Bitcoin exchange?:
Hi guys. I am using this CCXTbt library, and to be honnest, it's kinda hard getting it to work properly. I have a simple question: How ot have a fetch_ohlcv function work on an optimised time frame ? The thing is, I see this function running all the time, spamming the exchange with no reason. I think that instead, it should be called at a fixed time, like every minute, or every granularity, more generally speaking.
I am perfectly aware of the rateLimit parameter on the exchange, but I don't want to set a timeout between my API calls: I don't want any timeout between the time I fetch a ticker, and place an order, because a small wait can result in losing a bid or a sell.
Try this thread:
https://community.backtrader.com/topic/401/optimizing-with-ibstore-causes-redundant-connections-downloads/5A similar thing happens with IB on optimization. BT has the best answer at the end.
-
Hey guys awesome work you are doing here.
Is this the best fork to start with? https://github.com/bartosh/backtrader/tree/ccxt
I'm looking to trade bitmex, polonix, btcmarkets. -
You probably want to use a
Store
, rather than a fork (which had no good reason to be). Someone took the right approach extracting the code from the fork. -
Has anyone managed to use this on Bitmex ?
Using Rodrigo's code it starts ok and fetch the market data but after gets into a loop while trying to fetch open orders until I kill it ?[ __init__] init 2019-06-20 14:16:40.232891 - fetch_open_orders - Attempt 0 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Request: {'Content-Type': 'application/json', 'api-key': 'xxx', 'api-nonce': '1561036602233', 'api-signature': '30b4be8ae34bcda5190f5cc74e21f738c8e8337459587a2a2efec238f88bb412', 'Accept-Encoding': 'gzip, deflate'} None [_make_request] https://testnet.bitmex.com:443 "GET /api/v1/order?filter=%7B%22open%22%3Atrue%7D HTTP/1.1" 200 2 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Response: 200 {'Date': 'Thu, 20 Jun 2019 13:16:42 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '2', 'Connection': 'keep-alive', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '59', 'X-RateLimit-Reset': '1561036603', 'X-Powered-By': 'Profit', 'ETag': 'W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'} [] 2019-06-20 14:16:42.288010 - fetch_open_orders - Attempt 0 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Request: {'Content-Type': 'application/json', 'api-key': 'xxx', 'api-nonce': '1561036604289', 'api-signature': '077c17b5124f62b164c568bd30315277ca7f779f862b32c4ebb06730a1e8a539', 'Accept-Encoding': 'gzip, deflate'} None [_make_request] https://testnet.bitmex.com:443 "GET /api/v1/order?filter=%7B%22open%22%3Atrue%7D HTTP/1.1" 200 2 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Response: 200 {'Date': 'Thu, 20 Jun 2019 13:16:44 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '2', 'Connection': 'keep-alive', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '59', 'X-RateLimit-Reset': '1561036605', 'X-Powered-By': 'Profit', 'ETag': 'W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'} [] 2019-06-20 14:16:44.331896 - fetch_open_orders - Attempt 0 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Request: {'Content-Type': 'application/json', 'api-key': 'xxx', 'api-nonce': '1561036606332', 'api-signature': '8bc9b7d98138af4a248631260534a61d77fef496066da3701a222c4af5a9f1af', 'Accept-Encoding': 'gzip, deflate'} None [_make_request] https://testnet.bitmex.com:443 "GET /api/v1/order?filter=%7B%22open%22%3Atrue%7D HTTP/1.1" 200 2 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Response: 200 {'Date': 'Thu, 20 Jun 2019 13:16:46 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '2', 'Connection': 'keep-alive', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '59', 'X-RateLimit-Reset': '1561036607', 'X-Powered-By': 'Profit', 'ETag': 'W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'} [] 2019-06-20 14:16:46.383414 - fetch_open_orders - Attempt 0 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Request: {'Content-Type': 'application/json', 'api-key': 'xxx', 'api-nonce': '1561036608384', 'api-signature': 'b49377a1603d3557b58c13d688226b3d6117b62bdc09c10527c629b61ec104a9', 'Accept-Encoding': 'gzip, deflate'} None [_make_request] https://testnet.bitmex.com:443 "GET /api/v1/order?filter=%7B%22open%22%3Atrue%7D HTTP/1.1" 200 2 [ fetch] GET https://testnet.bitmex.com/api/v1/order?filter=%7B%22open%22%3Atrue%7D, Response: 200 {'Date': 'Thu, 20 Jun 2019 13:16:48 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '2', 'Connection': 'keep-alive', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '59', 'X-RateLimit-Reset': '1561036609', 'X-Powered-By': 'Profit', 'ETag': 'W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'} [] 2019-06-20 14:16:48.433256 - fetch_open_orders - Attempt 0 ^X^Cfinished.
-
@ed-bartosh
Hi Bartosh,Thank you for the implementation of ccxt in backtrader.
I'm trying to add 1 minute data to feed, and then resample it to 2 minutes data, so I can get MACD of 1 minute and MACD of 2 minutes in the Strategy.
But I'm keeping getting the error of:
ValueError: min() arg is an empty sequence
Here's the code:
# !/usr/bin/env python # -*- coding: utf-8; py-indent-offset:4 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import sys import time from datetime import datetime, timedelta from datetime import datetime, timedelta import backtrader as bt import ccxt class TestStrategy(bt.Strategy): params = ( ('printlog', True), ) def log(self, txt, dt=None, doprint=False): ''' Logging function fot this strategy''' if self.params.printlog or doprint: dt = dt or bt.num2date(self.data.datetime[0]) print('%s, %s' % (dt, txt)) def start(self): self.counter = 0 print('START') def prenext(self): self.counter += 1 print('prenext len %d - counter %d' % (len(self), self.counter)) def __init__(self): self.macd = bt.indicators.MACDHisto(self.datas[0]) self.macd2 = bt.indicators.MACDHisto(self.datas[1]) def next(self): self.counter += 1 price_txt = "Counter: " + str(self.counter) + " Open/Close/High/Low/Volume: " + str(self.data0.open[0]) + " - "+ str(self.data0.close[0]) + " - " + str(self.data0.high[0]) + " - " + str(self.data0.low[0]) + " - " + str(self.data0.volume[0]) + " Len: "+ str(len(self.data0))# + " Time Frame:" + bt.TimeFrame.getname(self.data0._timeframe) + " Len: "+ str(len(self.data0)) self.log(price_txt) macd_txt = "MACD: {:.2f}, Histo: {:.2f}".format(self.macd.macd[0],self.macd.histo[0]) self.log("MACD#1: " + macd_txt) macd2_txt = "MACD: {:.2f}, Histo: {:.2f}".format(self.macd2.macd[0],self.macd2.histo[0]) self.log("MACD#2: " + macd2_txt) if __name__ == '__main__': cerebro = bt.Cerebro() #exchange = sys.argv[1] if len(sys.argv) > 1 else 'gdax' exchange = sys.argv[1] if len(sys.argv) > 1 else 'okex' symbol = sys.argv[2] if len(sys.argv) > 2 else 'ETH/USDT' hist_start_date = datetime.utcnow() - timedelta(minutes=10) print('UTC NOW: ', datetime.utcnow()) print('hist_start_data: ', hist_start_date) print('Using symbol: ', symbol) # Create data feeds data_1m = bt.feeds.CCXT(exchange=exchange, symbol=symbol, name="1m", timeframe=bt.TimeFrame.Minutes, fromdate=hist_start_date,compression=1) cerebro.adddata(data_1m) cerebro.resampledata(data_1m, timeframe=bt.TimeFrame.Minutes, compression=2) cerebro.addstrategy(TestStrategy) cerebro.run()
The output is:
python stage1.py UTC NOW: 2019-06-21 05:41:48.784742 hist_start_data: 2019-06-21 05:31:48.784520 Using symbol: ETH/USDT START prenext len 1 - counter 1 prenext len 2 - counter 2 prenext len 3 - counter 3 prenext len 4 - counter 4 prenext len 5 - counter 5 prenext len 6 - counter 6 prenext len 7 - counter 7 prenext len 8 - counter 8 prenext len 9 - counter 9 prenext len 10 - counter 10 prenext len 11 - counter 11 prenext len 12 - counter 12 Traceback (most recent call last): File "stage1.py", line 66, in <module> cerebro.run() File "/Users/michael/.venv/backtrader-ccxt/lib/python3.6/site-packages/backtrader/cerebro.py", line 1127, in run runstrat = self.runstrategies(iterstrat) File "/Users/michael/.venv/backtrader-ccxt/lib/python3.6/site-packages/backtrader/cerebro.py", line 1298, in runstrategies self._runnext(runstrats) File "/Users/michael/.venv/backtrader-ccxt/lib/python3.6/site-packages/backtrader/cerebro.py", line 1557, in _runnext dt0 = min((d for i, d in enumerate(dts) ValueError: min() arg is an empty sequence
What am I doing wrong here?
Thank you.