Backtrader Community

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Fractional Position Size - oandav20store.py

    General Code/Help
    1
    2
    27
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mics
      mics last edited by

      I am trying to alter the oandav20store.py file to allow for fractional position sizes. The following function (in its original format) altered all create order sizes to be integers.

      When I delete the 'int' from the code and try to place an order with self.stake=1.4 it shows on OANDA activity as 'MARKET ORDER REJECT' with unit size 1.4.

      To test this with a hardcoded figure, if I replace the 'order.created.size' with '1.6' (just to be different), then the order is placed correctly and accepted by OANDA at 1.6 Units with a Stop at 1.6 Units.

      Anyone have idea on how to get order.created.size to work without being an integrer and equal the size of the buy order so that I can use self.stake as a dynamic variable?

      #PLACE ORDER
      self.stake = 1.4
      self.buy(exectype=bt.Order.Market, size=self.stake)
      self.sell(exectype=bt.Order.Stop, price=self.stop_loss, size=self.stake)
      

      From oandav20store.py:

          def order_create(self, order, stopside=None, takeside=None, **kwargs):
              '''Creates an order'''
              okwargs = dict()
              okwargs['instrument'] = order.data._dataname
              okwargs['units'] = (
                  #ORIGINAL CODE
                  #abs(int(order.created.size)) if order.isbuy()
                  #else -abs(int(order.created.size)))  # negative for selling
      
                  #DOES NOT WORK WITH 'int' REMOVED
                  abs(order.created.size) if order.isbuy()
                  else -abs(order.created.size))  # negative for selling
                  
                  #DOES WORK IF A FIXED DECIMAL VALUE IS USED FOR TESTING
                  #abs(1.6) if order.isbuy()
                  #else -abs(1.6))  # negative for selling
      
              okwargs['type'] = self._ORDEREXECS[order.exectype]
      
              if order.exectype != bt.Order.Market:
                  okwargs['price'] = format(
                      order.created.price,
                      '.%df' % order.data.contractdetails['displayPrecision'])
                  if order.valid is None:
                      okwargs['timeInForce'] = 'GTC'  # good to cancel
                  else:
                      okwargs['timeInForce'] = 'GTD'  # good to date
                      gtdtime = order.data.num2date(order.valid)
                      okwargs['gtdTime'] = gtdtime.strftime(self._DATE_FORMAT)
      
              if order.exectype == bt.Order.StopLimit:
                  okwargs['priceBound'] = order.created.pricelimit
      
              if order.exectype == bt.Order.StopTrail:
                  okwargs['distance'] = format(
                      order.trailamount,
                      '.%df' % order.data.contractdetails['displayPrecision'])
      
              if stopside is not None:
                  if stopside.exectype == bt.Order.StopTrail:
                      okwargs['trailingStopLossOnFill'] = v20.transaction.TrailingStopLossDetails(
                          distance=format(
                              stopside.trailamount,
                              '.%df' % order.data.contractdetails['displayPrecision']),
                          clientExtensions=v20.transaction.ClientExtensions(
                              id=str(stopside.ref)
                          ).dict()
                      ).dict()
                  else:
                      okwargs['stopLossOnFill'] = v20.transaction.StopLossDetails(
                          price=format(
                              stopside.price,
                              '.%df' % order.data.contractdetails['displayPrecision']),
                          clientExtensions=v20.transaction.ClientExtensions(
                              id=str(stopside.ref)
                          ).dict()
                      ).dict()
      
              if takeside is not None and takeside.price is not None:
                  okwargs['takeProfitOnFill'] = v20.transaction.TakeProfitDetails(
                      price=format(
                          takeside.price,
                          '.%df' % order.data.contractdetails['displayPrecision']),
                      clientExtensions=v20.transaction.ClientExtensions(
                          id=str(takeside.ref)
                      ).dict()
                  ).dict()
      
              # store backtrader order ref in client extensions
              okwargs['clientExtensions'] = v20.transaction.ClientExtensions(
                  id=str(order.ref)
              ).dict()
      
              okwargs.update(**kwargs)  # anything from the user
              self.q_ordercreate.put((order.ref, okwargs,))
      
              # notify orders of being submitted
              self.broker._submit(order.ref)
              if stopside is not None:  # don't make price on stopside mandatory
                  self.broker._submit(stopside.ref)
              if takeside is not None and takeside.price is not None:
                  self.broker._submit(takeside.ref)
      
              return order```
      1 Reply Last reply Reply Quote 0
      • mics
        mics last edited by

        SOLVED

        Turns out that OANDA needs to received the value as a string. The following changes to oandav20store.py now allow for fractional order sizes.

        Warning... make sure what ever sizer calculation you are using doesn't leave minor decimal positions open. Build your own sizer model!

            def order_create(self, order, stopside=None, takeside=None, **kwargs):
                '''Creates an order'''
                okwargs = dict()
                okwargs['instrument'] = order.data._dataname
                okwargs['units'] = (
                    #ORIGINAL CODE
                     #abs(int(order.created.size)) if order.isbuy()
                     #else -abs(int(order.created.size)))  # negative for selling
        
                    #NEW CODE: WORKS WITH FRACTIONAL ORDER SIZES
                    str(abs(order.created.size)) if order.isbuy()
                    else str(-abs(order.created.size)))  # negative for selling
        
        1 Reply Last reply Reply Quote 0
        • 1 / 1
        • First post
          Last post
        Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors