Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. stonks
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
    S
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 5
    • Best 1
    • Groups 0

    stonks

    @stonks

    1
    Reputation
    5
    Profile views
    5
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    stonks Unfollow Follow

    Best posts made by stonks

    • RE: Definition of margin param in setcommission unclear

      @ab_trader Thanks for your tip! I think I was able to code up a custom commission scheme (CommInfo_BinancePerp) that reproduces Binance perpetual futures where margin = position_value/mult. When I look at a minimal example of buying one contract and selling it a couple of days later, the numbers roughly add up but there is some mismatch between the buy price and the portfoliovalue/cash.

      I use this mini-example with (mult = 1), and (commission = 0) and the logs confuse me, If I start with 1000$, then buy one contract @ 396.36$, why do I have pvalue: 973.6$, cash: 590.44$ ? This can't even be explained by the difference between open/close on that day.

      My mini-example:

      import backtrader as bt
      from datetime import datetime
      
      class MiniExample(bt.Strategy):
      
          def __init__(self):
              # To keep track of pending orders
              self.orders = None
      
          def next(self):
                  if len(self) == 1: #on second candle
                      self.orders = self.buy(size = 1)
      
                  if len(self) == 5: #on 6th candle
                      self.orders = self.sell(size = 1)
      
                  dt = self.datas[0].datetime.date(0)
                  print(f"{dt} - getvalue: {round(self.broker.getvalue(),2)}$, getcash: {round(self.broker.getcash(),2)}$, getposition: {self.broker.getposition(self.datas[0]).size}, open: {self.datas[0].open[0]}$, close: {self.datas[0].close[0]}$")
      
          def log(self, txt, dt=None):
              ''' Logging function for this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
      
          def notify_order(self, order):
      
              if order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
                  print('Order Canceled/Margin/Rejected')
      
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
      
              # Check if an order has been completed
              # Attention: broker could reject order if not enough cash
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.log(f"BUY EXECUTED, {order.executed.size} units @ {order.executed.price}$")
                  elif order.issell():
                      self.log(f"SELL EXECUTED, {order.executed.size} units @ {order.executed.price}$")
      
                  self.bar_executed = len(self)
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
              # Write down: no pending order
              self.orders = None
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
      
      # define custom commission scheme that reproduces Binance perpetual future trading
      class CommInfo_BinancePerp(bt.CommInfoBase):
          params = (
            ('stocklike', False),  # Futures
            ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
          )
      
          def _getcommission(self, size, price, pseudoexec):
              return size * price * self.p.commission * self.p.mult
      
          def get_margin(self, price):
              return price / self.p.mult
      
          def getsize(self, price, cash):
              '''Returns fractional size for cash operation @price'''
              return self.p.mult * (cash / price)
      
      
      # initialize cerebro object
      cerebro = bt.Cerebro()
      
      # add strategy
      cerebro.addstrategy(MiniExample)
      
      # add custom commission scheme to cerebro element
      binance_leverage = 1
      
      comminfo = CommInfo_BinancePerp(
          commission=0,  # 0.1%
          mult=binance_leverage
      )
      cerebro.broker.addcommissioninfo(comminfo)
      
      cerebro.broker.set_shortcash(False)
      
      # set initial cash
      cerebro.broker.setcash(1000)
      
      # add data
      data = bt.feeds.YahooFinanceData(dataname='ETH-USD', fromdate = datetime(2020,11,1), todate = datetime(2020,11,7))
      cerebro.adddata(data)
      
      # execute
      back = cerebro.run()
      

      My logs:

      2020-11-01 - pvalue: 1000.0$, cash: 1000.0$, pos: 0, O: 386.59$, C: 396.36$
      2020-11-02, BUY EXECUTED, 1 units @ 396.36$
      2020-11-02 - pvalue: 973.6$, cash: 590.44$, pos: 1, O: 396.36$, C: 383.16$
      2020-11-03 - pvalue: 982.48$, cash: 594.88$, pos: 1, O: 383.16$, C: 387.6$
      2020-11-04 - pvalue: 1011.56$, cash: 609.42$, pos: 1, O: 387.6$, C: 402.14$
      2020-11-05 - pvalue: 1035.42$, cash: 621.35$, pos: 1, O: 402.14$, C: 414.07$
      2020-11-06, SELL EXECUTED, -1 units @ 414.07$
      2020-11-06, OPERATION PROFIT, GROSS 17.71, NET 17.71
      2020-11-06 - pvalue: 1017.71$, cash: 1017.71$, pos: 0, O: 414.07$, C: 454.72$
      

      Thanks again for any further help, really struggling with this.

      posted in General Code/Help
      S
      stonks

    Latest posts made by stonks

    • RE: Definition of margin param in setcommission unclear

      @ab_trader Thanks for your tip! I think I was able to code up a custom commission scheme (CommInfo_BinancePerp) that reproduces Binance perpetual futures where margin = position_value/mult. When I look at a minimal example of buying one contract and selling it a couple of days later, the numbers roughly add up but there is some mismatch between the buy price and the portfoliovalue/cash.

      I use this mini-example with (mult = 1), and (commission = 0) and the logs confuse me, If I start with 1000$, then buy one contract @ 396.36$, why do I have pvalue: 973.6$, cash: 590.44$ ? This can't even be explained by the difference between open/close on that day.

      My mini-example:

      import backtrader as bt
      from datetime import datetime
      
      class MiniExample(bt.Strategy):
      
          def __init__(self):
              # To keep track of pending orders
              self.orders = None
      
          def next(self):
                  if len(self) == 1: #on second candle
                      self.orders = self.buy(size = 1)
      
                  if len(self) == 5: #on 6th candle
                      self.orders = self.sell(size = 1)
      
                  dt = self.datas[0].datetime.date(0)
                  print(f"{dt} - getvalue: {round(self.broker.getvalue(),2)}$, getcash: {round(self.broker.getcash(),2)}$, getposition: {self.broker.getposition(self.datas[0]).size}, open: {self.datas[0].open[0]}$, close: {self.datas[0].close[0]}$")
      
          def log(self, txt, dt=None):
              ''' Logging function for this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
      
          def notify_order(self, order):
      
              if order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
                  print('Order Canceled/Margin/Rejected')
      
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
      
              # Check if an order has been completed
              # Attention: broker could reject order if not enough cash
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.log(f"BUY EXECUTED, {order.executed.size} units @ {order.executed.price}$")
                  elif order.issell():
                      self.log(f"SELL EXECUTED, {order.executed.size} units @ {order.executed.price}$")
      
                  self.bar_executed = len(self)
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
              # Write down: no pending order
              self.orders = None
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
      
      # define custom commission scheme that reproduces Binance perpetual future trading
      class CommInfo_BinancePerp(bt.CommInfoBase):
          params = (
            ('stocklike', False),  # Futures
            ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
          )
      
          def _getcommission(self, size, price, pseudoexec):
              return size * price * self.p.commission * self.p.mult
      
          def get_margin(self, price):
              return price / self.p.mult
      
          def getsize(self, price, cash):
              '''Returns fractional size for cash operation @price'''
              return self.p.mult * (cash / price)
      
      
      # initialize cerebro object
      cerebro = bt.Cerebro()
      
      # add strategy
      cerebro.addstrategy(MiniExample)
      
      # add custom commission scheme to cerebro element
      binance_leverage = 1
      
      comminfo = CommInfo_BinancePerp(
          commission=0,  # 0.1%
          mult=binance_leverage
      )
      cerebro.broker.addcommissioninfo(comminfo)
      
      cerebro.broker.set_shortcash(False)
      
      # set initial cash
      cerebro.broker.setcash(1000)
      
      # add data
      data = bt.feeds.YahooFinanceData(dataname='ETH-USD', fromdate = datetime(2020,11,1), todate = datetime(2020,11,7))
      cerebro.adddata(data)
      
      # execute
      back = cerebro.run()
      

      My logs:

      2020-11-01 - pvalue: 1000.0$, cash: 1000.0$, pos: 0, O: 386.59$, C: 396.36$
      2020-11-02, BUY EXECUTED, 1 units @ 396.36$
      2020-11-02 - pvalue: 973.6$, cash: 590.44$, pos: 1, O: 396.36$, C: 383.16$
      2020-11-03 - pvalue: 982.48$, cash: 594.88$, pos: 1, O: 383.16$, C: 387.6$
      2020-11-04 - pvalue: 1011.56$, cash: 609.42$, pos: 1, O: 387.6$, C: 402.14$
      2020-11-05 - pvalue: 1035.42$, cash: 621.35$, pos: 1, O: 402.14$, C: 414.07$
      2020-11-06, SELL EXECUTED, -1 units @ 414.07$
      2020-11-06, OPERATION PROFIT, GROSS 17.71, NET 17.71
      2020-11-06 - pvalue: 1017.71$, cash: 1017.71$, pos: 0, O: 414.07$, C: 454.72$
      

      Thanks again for any further help, really struggling with this.

      posted in General Code/Help
      S
      stonks
    • RE: Definition of margin param in setcommission unclear

      @ab_trader Is there a way to specify the margin as a percentage of the asset price, rather than as an absolute value, in backtrader? Otherwise, how does the margin requirement change over time as the price of the future changes?

      posted in General Code/Help
      S
      stonks
    • RE: Definition of margin param in setcommission unclear

      @ab_trader Thanks! On the link you posted they also explain that the futures margin is a fixed amount of cash that needs to be deposited before futures can be traded. Excuse me if this is a really dumb question, but won't this be a) dependent on the position size I intend to open and b) change with time? I'm interested in the case of Binance perpetual futures where the initial margin clearly is given as a fraction of the position value and the applied leverage (https://www.binance.com/de/support/faq/360033162192-Leverage-and-Margin-of-Perpetual-Futures-Contracts). Thanks for helping out a rookie

      posted in General Code/Help
      S
      stonks
    • Definition of margin param in setcommission unclear

      Hello everyone, I'm wondering what the definition of the margin parameter in the commission schemes is. It is not really defined well on https://www.backtrader.com/docu/commission-schemes/commission-schemes/ . Shouldn't the margin requirement be a relative parameter depending on the size of the order? Here it appears to be a fixed monetary value (2000) :

      cerebro.broker.setcommission(commission=2.0, margin=2000.0, mult=10.0)
      

      Thanks,
      Cheers

      posted in General Code/Help
      S
      stonks
    • perpetual futures equivalent on backtrader

      Hello everyone,

      First of all, thanks for this awesome platform and this community forum. I have been a silent reader up until now but could need some help with the issue below to continue my algo trading journey:

      What I want to do:
      Test various trading strategies on perpetual future contracts as offered on Binance.

      What I can do:
      I understand the basic platform concepts (as far as i know, please correct me on this one if I'm mistaken) and can code up strategies for stock like assets, code up indicators, load data etc.

      What doesn't work / what I'm unsure about:
      I would like to configure the platform in a way that most accurately replicates cryptocurrency future trading on Binance. The discussion given in https://community.backtrader.com/topic/2132/unable-to-figure-out-leverage didn't help me to figure out what exactly i need in my case.

      From my understanding I need the following settings:

      1

      cerebro.broker.set_shortcash(False)
      

      (we don't actually receive cash when we buy perpetual short contracts on Binance)

      2

      cerebro.broker.setcommission(commission=0.0015, margin = None, mult = 2)
      

      (indicates the commission for futures trades and the "leverage" on binance which is actually a multiplier if I get that right.)

      Has anyone configured the platform for this case before? I'm running into trouble with rejected orders especially when trading several assets. On Binance, if I have 100$ and set the leverage to 2X that means that I can buy future contracts with a value of 110$ without any risk of rejection. It seems like this doesn't work on backtrader (using target_order_value or target_order_percent) with my current settings. If required, I will provide a code example but I presume this is a fairly general problem that is better described without example.

      Thanks for your help,
      stonks

      posted in General Code/Help
      S
      stonks