For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Anyone use backtrader to do live trading on Bitcoin exchange?



  • Thanks @Ed-Bartosh for all your work on this.

    Running a slightly modified version of your minimal example:

    #!/usr/bin/env python
    # -*- coding: utf-8; py-indent-offset:4 -*-
    ###############################################################################
    #
    # Copyright (C) 2017 Ed Bartosh
    #
    # This program is free software: you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    #
    ###############################################################################
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import sys
    import time
    import ccxt
    
    from datetime import datetime, timedelta
    
    import backtrader as bt
    
    class TestStrategy(bt.Strategy):
        def next(self):
            for data in self.datas:
                print('*' * 5, 'NEXT:', bt.num2date(data.datetime[0]), data._name, data.open[0], data.high[0],
                      data.low[0], data.close[0], data.volume[0],
                      bt.TimeFrame.getname(data._timeframe), len(data))
                if not self.getposition(data):
                    order = self.buy(data, exectype=bt.Order.Limit, size=10, price=0.069)
                else:
                    order = self.sell(data, exectype=bt.Order.Limit, size=10, price=0.07)
    
        def notify_order(self, order):
            print('*' * 5, "NOTIFY ORDER", order)
    
    def runstrategy(argv):
        # Create a cerebro
        cerebro = bt.Cerebro()
    
        # Create broker
        broker_config = {'urls': {'api': 'https://api.sandbox.gemini.com'},
                         'apiKey': 'lnedXPZCM71YNDdfXRol',
                         'secret': '2SoHTmuUAC6AAiAd1bgtSrALo64g', 
                         'nonce': lambda: str(int(time.time() * 1000))
                        }
        broker = bt.brokers.CCXTBroker(exchange='gemini', currency='USD', config=broker_config)
        cerebro.setbroker(broker)
    
        # # Create data feeds
        # data_ticks = bt.feeds.CCXT(exchange='gdax', symbol='BTC/USD', name="btc_usd_tick",
        #                            timeframe=bt.TimeFrame.Ticks, compression=5)
        # cerebro.adddata(data_ticks)
    
        hist_start_date = datetime.utcnow() - timedelta(minutes=30)
        data_min = bt.feeds.CCXT(exchange="binance", 
                                symbol="ETH/BTC", 
                                # name="btc_usd_min",
                                timeframe=bt.TimeFrame.Minutes, 
                                fromdate=hist_start_date)
        cerebro.adddata(data_min)
    
        # Add the strategy
        cerebro.addstrategy(TestStrategy)
    
        # Run the strategy
        cerebro.run()
    
    if __name__ == '__main__':
        sys.exit(runstrategy(sys.argv))
    
    

    My error is:

    $ python gemini-ccxt-test.py
    ***** NEXT: 2018-07-31 14:17:00  0.055565 0.05561 0.055546 0.055593 133.594 Minute 1
    Traceback (most recent call last):
      File "gemini-ccxt-test.py", line 79, in <module>
        sys.exit(runstrategy(sys.argv))
      File "gemini-ccxt-test.py", line 76, in runstrategy
        cerebro.run()
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/cerebro.py", line 1127, in run
        runstrat = self.runstrategies(iterstrat)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/cerebro.py", line 1298, in runstrategies
        self._runnext(runstrats)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/cerebro.py", line 1630, in _runnext
        strat._next()
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/strategy.py", line 325, in _next
        super(Strategy, self)._next()
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/lineiterator.py", line 268, in _next
        self.nextstart()  # only called for the 1st value
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/lineiterator.py", line 342, in nextstart
        self.next()
      File "gemini-ccxt-test.py", line 41, in next
        order = self.sell(data, exectype=bt.Order.Limit, size=10, price=0.07)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/strategy.py", line 947, in sell
        **kwargs)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 102, in sell
        return self._submit(owner, data, exectype, 'sell', size, price, kwargs)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 88, in _submit
        order = CCXTOrder(owner, data, _order)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/metabase.py", line 88, in __call__
        _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/metabase.py", line 78, in doinit
        _obj.__init__(*args, **kwargs)
      File "/Users/tw/.local/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 33, in __init__
        self.ordtype = self.Buy if ccxt_order['side'] == 'buy' else self.Sell
    KeyError: 'side'
    

    This could just be an error related to using Gemini, although I don't know, and I don't want to set any bots on my Binance account at the moment!

    Thanks for any help.



  • @tw00000 Thank you for the great report. It should be fixed now by this commit. Please, try it and let us know if it works for you.

    PS: I've rebased my ccxt branch on top of the latest backtrader release 1.9.65.122 and tested it with the latest ccxt release 1.17.76



  • Hi @Ed-Bartosh -
    i am getting this error - looks like versioning issue?

    in one of the ccxtbroker.py versions you published we had this line:
    ccxt_order = self.ccxt.exchange.create_order(symbol=data.ccxt.symbol, type=order_type, side=side, amount=amount, price=price, params=params)

    and i got this error:

    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 96, in buy
    return self._submit(owner, data, exectype, 'buy', size, price, kwargs)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 86, in _submit
    _order = self.store.create_order(symbol=data.symbol, order_type=order_type, side=side,
    File "/anaconda3/lib/python3.6/site-packages/backtrader/lineseries.py", line 461, in getattr
    return getattr(self.lines, name)
    AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'symbol'



  • @samy-david Thank you for the report. Can you provide more details, please? Which version of my code and ccxt do you use?



  • @ed-bartosh i am using your fork with the latest bt (1.9.65.122)
    including this commit for fixing the keyerror

    also including this commit
    for merging the CCXTOrder into the CCXTStore.

    I am sure i lost sync somewhere ... can you kindly supply the step by step for re-installing BT and CCXT ?



  • @samy-david I don't think you lost sync as far as I can see from the traceback. Can you show simple code to reproduce this issue?



  • @ed-bartosh

    i am passing the data received in notify_order to the broker buy/sell method

    self.broker.sell(owner=self,data=order.data, exectype=Order.Limit,
    size=limit_size, price=price)

    then the Error is as following:
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 92, in sell
    return self._submit(owner, data, exectype, 'sell', size, price, kwargs)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 76, in _submit
    _order = self.store.create_order(symbol=data.symbol, order_type=order_type, side=side,
    File "/anaconda3/lib/python3.6/site-packages/backtrader/lineseries.py", line 461, in getattr
    return getattr(self.lines, name)
    AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'symbol'



  • @samy-david said in Anyone use backtrader to do live trading on Bitcoin exchange?:

    self.broker.sell(owner=self,data=order.data, exectype=Order.Limit,
    size=limit_size, price=price)

    What's order.data in your example? It's definitely not a CCXT feed data as it doesn't have 'symbol' attribute, which causes ccxtbroker failure.



  • @ed-bartosh
    the data comes form the strategy - self.datas - the single data object is passed to the order:
    order_op = self.broker.sell
    :
    order_op(owner=self,data=data, size=order_size, exectype=Order.Market)

    the data is then returned as part of notify_order and forward to a limit order
    :
    self.broker.sell(owner=self,data=order.data, exectype=Order.Limit,
    size=limit_size, price=price)

    cerebro feed is defined as following:
    data = bt.feeds.CCXT(exchange='bitmex', symbol='BTC/USD', name="btc_usd_min",
    timeframe=bt.TimeFrame.Minutes, compression=1,backfill_start=True,fromdate=hist_start_date,config=feed_config)

    Resample of data
    cerebro.resampledata(data,name="btc_usd_min",timeframe=bt.TimeFrame.Minutes, compression=5)

    here is a simple print of the object from the log
    data <backtrader.feeds.ccxt.CCXT object at 0x10b076588>



  • @ed-bartosh

    i did further digging into the code and i think could be a CCXT issue.
    there are few reasons that could trigger the issue:

    Reason 1:
    the missing symbol comes from resampled data -

    • i fetch the historical data in 1m compression
    • i resample the data to 1 & 2 minutes (and higher ...)

    -- update - 1m timeframe data exists, all other timeframes (resample/replay) come with a missing symbol and potentially other data

    the log shows a successful order for 1 minute signal, but missing the data for higher TF's:

    Reason 2:
    i think i saw a thread about loading historical data doesn't work for IB's - could it be a similar issue?
    found it ... (this issue)

    -- update - although related, it is not relevant for our case here , i ran the process with only live data (not historical) and still there was an issue

    Reason 3
    should i use replay data instead of resample data for higher TFs ?
    so 1m is resampled, and all higher TFs are replayed - could this fix the missing data?

    -- update - i tried running higher TFs with replay, still same error

    Reason 4
    looking at the _GRANULARITIES in ccxtstore - i was using 2m TFs - could this be the issue? (unsupported TF) ?

    • update - this could be a potential candidate, however i ran it with supported TFs and still same error:

    as a reference - here is the error from the log:

    this line is my code -
    order_op(owner=self,data=data, size=order_size, exectype=Order.Market)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 88, in buy
    return self._submit(owner, data, exectype, 'buy', size, price, kwargs)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 77, in _submit
    _order = self.store.create_order(symbol=data.symbol, order_type=order_type, side=side,
    File "/anaconda3/lib/python3.6/site-packages/backtrader/lineseries.py", line 461, in getattr
    return getattr(self.lines, name)
    AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'symbol'



  • @samy-david said in Anyone use backtrader to do live trading on Bitcoin exchange?:

    1m timeframe data exists, all other timeframes (resample/replay) come with a missing symbol and potentially other data

    I can't reproduce it. I can see 'symbol' attribute in the data after resampling:

    $ ./test.py 
    data.symbol after resampling: BTC/USD
    
    $ cat test.py 
    #!/usr/bin/env python
    
    import sys
    import backtrader as bt
    
    cerebro = bt.Cerebro()
    
    data = bt.feeds.CCXT(exchange="bitmex", symbol="BTC/USD", timeframe=bt.TimeFrame.Minutes)
    
    cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=2)
    
    print("data.symbol after resampling:", data.symbol)
    


  • @samy-david said in Anyone use backtrader to do live trading on Bitcoin exchange?:

    self.broker.sell(owner=self,data=order.data, exectype=Order.Limit, size=limit_size, price=price)

    What's the reason to use self.broker.sell instead of self.sell?

    Can you sketch small script that I can run to reproduce the issue? Without this it'll be guessing game and it can take much longer.



  • Dear CCXT adopters,

    I have a question regarding base currencies in pairs trading that you might have solved:

    • My "backtrader currency" (value of account at broker etc) is USD, as I want all data in USD
    • I trade alt coins vs BTC or also vs ETH. So for example, I would go long LTC/BTC and at the same time short IOT/ETH

    How can I handle that in backtrader? The problem is that the system assumes that all prices are in USD, so backtrader assumes that my LTC/BTC price feed is a price in USD, which messes up position sizing, portfolio composition, etc.

    If someone ran into the same issue and could share his solution that would be highly appreciated!

    Thanks,
    JF



  • I am still having the same issue while pulling data from Bitmex; the live data is all unfinished. Has this issue been resolved? Anybody else still getting it?

    @fivo said in Anyone use backtrader to do live trading on Bitcoin exchange?:

    @fivo said in Anyone use backtrader to do live trading on Bitcoin exchange?:

    There seems to be a problem when fetching live data. The backfilling works correctly, but once the live data is used the feeds receives the data of the current minute (assuming we are trading minute data) that is not yet finished. Essentially the opening value is correct, but the rest (close high low vol) is not.

    It doesn't seem to be ccxt as the following little script produces the correct values. I think the code around this line seems to be fetching data as soon as some data of the currently running minute is available. I will try look into it.

    # !/usr/bin/env python
    # -*- coding: utf-8; py-indent-offset:4 -*-
    
    from datetime import datetime, timedelta
    import time
    
    import ccxt
    
    binance = ccxt.binance()
    
    while True:
        fromdate = datetime.utcnow() - timedelta(minutes=2)
        since = int((fromdate - datetime(1970, 1, 1)).total_seconds() * 1000)
        ohlcvs = binance.fetch_ohlcv('BTC/USDT', '1m', since=since, limit=1)
        if not ohlcvs:
            continue
    
        ohlcv = ohlcvs[0]
    
        print(datetime.utcfromtimestamp(ohlcv[0]/1000), ohlcv[1], ohlcv[2],
              ohlcv[3], ohlcv[4], ohlcv[5])
    
        time.sleep(1)
    

    Can anybody reproduce this issue?



  • @john-land i think i have the same issue - not sure if it is related.

    but the data from cerebro is missing symbol

    File "/anaconda3/lib/python3.6/site-packages/backtrader/strategy.py", line 917, in buy
    **kwargs)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 88, in buy
    return self._submit(owner, data, exectype, 'buy', size, price, kwargs)
    File "/anaconda3/lib/python3.6/site-packages/backtrader/brokers/ccxtbroker.py", line 77, in _submit
    _order = self.store.create_order(symbol=data.symbol, order_type=order_type, side=side,
    File "/anaconda3/lib/python3.6/site-packages/backtrader/lineseries.py", line 461, in getattr
    return getattr(self.lines, name)
    AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'symbol'



  • @ed-bartosh i am using Ichimoku indicator which require a history of 120 candles for 1 minute - so for 5 minutes it is 600 candles. i am loading 720.

    i think this is some how related to the post @John-Land mentioned about incomplete data.



  • @Ed-Bartosh I have a special use case.
    I'm trying to setup a live feed for Bitstamp and using indicators requires backfilling as well.

    The problem I'm facing is that bitstamp doesn't offer ohlcv data as part of it's API's. (i'm assuming ohlcv is required)

    side note:
    Didn't find any reference in the code to the use of 'backfill_start'?

    I have the historical data in a .csv file. is there a way maybe to stitch the two together?

    found this in ibdata.py:

      ``backfill_from`` (default: ``None``)
    
       An additional data source can be passed to do an initial layer of
    
       backfilling. Once the data source is depleted and if requested,
    
       backfilling from IB will take place. This is ideally meant to backfill
    
       from already stored sources like a file on disk, but not limited to.


  • @jacob

    I have the historical data in a .csv file. is there a way maybe to stitch the two together?

    Currently backfill_from is not supported. I'll be happy to see this implemented. I hope it's not that hard to implement considering working example from ibdata.py.



  • I've been using backtrader for sometime but I'm new to the ccxt live data. Thank you @Ed-Bartosh for all the work you've done on this. amazing!

    When using live data I'm noticing quite a significant delay of the data by about 30 seconds or so. Is this expected behavior? My hope is to run this as close to real-time as possible.

    Even though the data status shows LIVE, the first data is actually about 15mins behind real-time but starts to catch up after around 30 seconds, although it never actually fully catches up and ends up always being about 10-15 seconds behind the real-time data. I'm using TradingView and pro.coinbase.com as my benchmark as I'm using gdax as the feed.

    ***** DATA NOTIF: LIVE
    ***** NEXT: 2018-08-21 08:15:33.492003 btc_usd_tick 6475.01 6475.01 6475.01 6475.01 0.01 Tick 1
    ***** NEXT: 2018-08-21 08:15:33.532004 btc_usd_tick 6475.91 6475.91 6475.91 6475.91 0.57164401 Tick 2
    ***** NEXT: 2018-08-21 08:15:46.381995 btc_usd_tick 6475.91 6475.91 6475.91 6475.91 0.0016879 Tick 3
    ***** NEXT: 2018-08-21 08:15:53.060997 btc_usd_tick 6475.9 6475.9 6475.9 6475.9 0.0034 Tick 4
    ***** NEXT: 2018-08-21 08:16:04.493001 btc_usd_tick 6475.91 6475.91 6475.91 6475.91 0.0028 Tick 5
    ***** NEXT: 2018-08-21 08:16:16.126000 btc_usd_tick 6475.9 6475.9 6475.9 6475.9 0.0097 Tick 6
    ***** NEXT: 2018-08-21 08:16:28.048999 btc_usd_tick 6475.9 6475.9 6475.9 6475.9 0.1667 Tick 7
    ***** NEXT: 2018-08-21 08:16:45.003001 btc_usd_tick 6475.9 6475.9 6475.9 6475.9 1.0 Tick 8
    ***** NEXT: 2018-08-21 08:16:45.043002 btc_usd_tick 6474.6 6474.6 6474.6 6474.6 0.001 Tick 9
    ***** NEXT: 2018-08-21 08:16:49.953004 btc_usd_tick 6471.01 6471.01 6471.01 6471.01 0.00345867 Tick 10
    ***** NEXT: 2018-08-21 08:16:50.023995 btc_usd_tick 6471.01 6471.01 6471.01 6471.01 0.045419 Tick 11
    ***** NEXT: 2018-08-21 08:17:05.876002 btc_usd_tick 6471.01 6471.01 6471.01 6471.01 0.15756512 Tick 12
    ***** NEXT: 2018-08-21 08:17:10.691003 btc_usd_tick 6471.01 6471.01 6471.01 6471.01 0.0079974 Tick 13
    ***** NEXT: 2018-08-21 08:17:17.021002 btc_usd_tick 6471.01 6471.01 6471.01 6471.01 0.00315375 Tick 14
    ***** NEXT: 2018-08-21 08:17:21.066002 btc_usd_tick 6468.35 6468.35 6468.35 6468.35 0.00062 Tick 15
    ***** NEXT: 2018-08-21 08:17:21.703003 btc_usd_tick 6467.06 6467.06 6467.06 6467.06 0.01 Tick 16
    ***** NEXT: 2018-08-21 08:17:49.377999 btc_usd_tick 6465.19 6465.19 6465.19 6465.19 0.03187985 Tick 17
    ***** NEXT: 2018-08-21 08:18:01.357998 btc_usd_tick 6465.19 6465.19 6465.19 6465.19 0.0515 Tick 18
    ***** NEXT: 2018-08-21 08:18:04.042001 btc_usd_tick 6465.2 6465.2 6465.2 6465.2 0.00384762 Tick 19
    ***** NEXT: 2018-08-21 08:18:11.765002 btc_usd_tick 6465.19 6465.19 6465.19 6465.19 0.00383559 Tick 20
    ***** NEXT: 2018-08-21 08:18:11.801997 btc_usd_tick 6465.0 6465.0 6465.0 6465.0 4.99793959 Tick 21
    
    class TestStrategy(bt.Strategy):
        def next(self):
            for data in self.datas:
                print('*' * 5, 'NEXT:', bt.num2date(data.datetime[0]), data._name, data.open[0], data.high[0],
                      data.low[0], data.close[0], data.volume[0],
                      bt.TimeFrame.getname(data._timeframe), len(data))
    
        def notify_order(self, order):
            print('*' * 5, "NOTIFY ORDER", order)
            
        def notify_data(self, data, status, *args, **kwargs):
            print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args)
    
    def runstrategy(argv):
        # Create a cerebro
        cerebro = bt.Cerebro()
    
        # Create broker
        broker_config = {'urls': {'api': 'https://api.pro.coinbase.com'},
                         'apiKey': '{}'.format(gdax.apiKey),
                         'secret': '{}'.format(gdax.secret),
                         'password': '{}'.format(gdax.password)
                        }
    
        # Create data feeds
        data_ticks = bt.feeds.CCXT(exchange='gdax', symbol='BTC/USD', name="btc_usd_tick",
                                   timeframe=bt.TimeFrame.Ticks, compression=1)
        cerebro.adddata(data_ticks)
    
        # Add the strategy
        cerebro.addstrategy(TestStrategy)
    
        # Run the strategy
        cerebro.run()
    


  • I noticed something strange with the ccxt fetchohlc() in that sometimes it returns candles up to the last closed candle and sometimes it returns the current live (not yet closed candle).

    I used the follow code to get the last 20 candles which uses the same method that the ccxt backtrader uses to get live candle data.

    df = pd.DataFrame(gdax.fetchOhlcv('BTC/USD', timeframe='1m', limit=20))
    df['Date'] = pd.to_datetime(df[0], unit='ms')
    df.set_index('Date', inplace=True)
    df.drop(0, axis=1, inplace=True)
    df.columns = ['open', 'high','low','close','volume']
    df['highlow'] = df['high'] - df['low']; df
    

    This outputs a dataframe:

                               
    Date	                open    high    low     close   volume        highlow
    2018-08-21 09:15:00	6452.99	6453.00	6452.99	6452.99	0.382287	0.01
    2018-08-21 09:16:00	6453.00	6453.00	6452.99	6453.00	0.231581	0.01
    2018-08-21 09:17:00	6453.00	6453.00	6453.00	6453.00	0.033058	0.00
    2018-08-21 09:18:00	6453.00	6453.00	6452.99	6453.00	0.244911	0.01
    2018-08-21 09:19:00	6453.00	6453.00	6452.99	6452.99	2.142046	0.01
    2018-08-21 09:20:00	6453.00	6453.00	6438.91	6441.62	10.994071	14.09
    2018-08-21 09:21:00	6441.62	6445.98	6441.62	6445.98	1.862376	4.36
    2018-08-21 09:22:00	6445.97	6445.97	6431.64	6437.10	12.625005	14.33
    2018-08-21 09:23:00	6437.10	6445.67	6437.10	6443.40	1.902326	8.57
    2018-08-21 09:24:00	6443.39	6443.40	6443.39	6443.39	0.531487	0.01
    2018-08-21 09:25:00	6443.40	6443.40	6435.62	6435.62	1.435376	7.78
    2018-08-21 09:26:00	6436.35	6437.32	6433.71	6433.71	1.582333	3.61
    2018-08-21 09:27:00	6435.23	6435.23	6435.22	6435.22	0.054494	0.01
    2018-08-21 09:28:00	6435.22	6436.00	6435.22	6436.00	0.099945	0.78
    2018-08-21 09:29:00	6435.99	6435.99	6433.71	6433.71	1.374433	2.28
    2018-08-21 09:30:00	6433.71	6433.71	6431.00	6432.77	1.015340	2.71
    2018-08-21 09:31:00	6433.62	6433.62	6432.76	6433.00	0.172707	0.86
    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    2018-08-21 09:34:00	6431.63	6431.63	6431.63	6431.63	0.059508	0.00
    

    When I ran this 4 times consecutively within less than 1 second I got the following results (only last 3 lines shown)

    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    2018-08-21 09:34:00	6431.63	6431.63	6431.63	6431.63	0.059508	0.00
    
    2018-08-21 09:31:00	6433.62	6433.62	6432.76	6433.00	0.172707	0.86
    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    
    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    2018-08-21 09:34:00	6431.63	6431.63	6431.63	6431.63	0.062508	0.00
    
    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    2018-08-21 09:34:00	6431.63	6431.63	6431.63	6431.63	0.059508	0.00
    

    As you can see, sometimes it returns the 9:34 candle (which at the time had not closed) and sometimes it returns the 9:33 candle (which has closed) as the most recent.

    When I ran this a few minutes later I get

    2018-08-21 09:32:00	6432.99	6433.00	6432.99	6432.99	0.555686	0.01
    2018-08-21 09:33:00	6432.99	6432.99	6427.75	6431.62	3.599003	5.24
    2018-08-21 09:34:00	6431.63	6433.00	6431.62	6433.00	4.551569	1.38
    2018-08-21 09:35:00	6433.38	6434.68	6433.38	6434.68	12.601649	1.30
    2018-08-21 09:36:00	6436.36	6444.00	6436.36	6443.99	3.252023	7.64
    

    As you can see the 9:34 candle closed at 6433.00 not at 6431.63.

    This means that when you are getting 1m live data from backtrader you may actually be getting a live candle instead of the actual data because backtrader/ccxt will record the time of the latest candle and only give candles with timestamps later than the previous.

    In fact this actually looks like what I'm getting

    ***** DATA NOTIF: LIVE
    ***** NEXT: 2018-08-21 09:04:00 btc_usd_min 6459.99 6460.0 6459.99 6460.0 0.02234232 Minute 3
    ***** NEXT: 2018-08-21 09:05:00 btc_usd_min 6455.06 6455.06 6455.06 6455.06 0.05325761 Minute 4
    ***** NEXT: 2018-08-21 09:06:00 btc_usd_min 6455.06 6460.92 6455.06 6460.92 0.75941057 Minute 5
    ***** NEXT: 2018-08-21 09:07:00 btc_usd_min 6460.95 6460.95 6460.95 6460.95 0.00362068 Minute 6
    ***** NEXT: 2018-08-21 09:08:00 btc_usd_min 6457.84 6457.84 6457.84 6457.84 0.03702458 Minute 7
    ***** NEXT: 2018-08-21 09:09:00 btc_usd_min 6452.82 6452.82 6452.82 6452.82 1.21548925 Minute 8
    ***** NEXT: 2018-08-21 09:10:00 btc_usd_min 6452.81 6452.81 6452.81 6452.81 0.0226 Minute 9
    

    Minute 5 appears to be a full candle whereas Minute 7 (for example) appears to be a partially completed live candle