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