Navigation

    Backtrader Community

    • Register
    • 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/

    Need help/advice for dynamically implementing commissions

    General Code/Help
    4
    7
    529
    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.
    • J
      jacksonX last edited by

      Hi backtraders, I'm trying to backtest several covered call strategies using ETF futures and ETF options. My ETF options have complicated margin requirements, and I'm now stuck with setting the desired commission schemes in backtrader. I'm hoping experienced members can kindly me enlighten me here. Many thanks in advance!

      so the story goes:

      Unlike the simple future-like or stock-like commission schemes in backtrader, where the commission is either a fixed percent of the underlying asset price (I've read the page on Custom Schemes, but it doesn't help me much here) or a fixed amount, my ETF options need commission AND a dynamically calculated margin. There are four timeseries variables to calculate its margin, including:

      • last-day option settlement price,
      • last-day option close price,
      • the amount that the option is in-the-money, and
      • the size of the short position (long position doen't need margin).

      Basically, I need an interface where I can push 'lines' (time-series) rather than fixed 'parameters' into a customised class subclassed from CommInfoBase, where I perform the calculations.

      Please kindly help, advice or comment here.

      ps: I'm trying to push forward a backtrader-based option backtesting project. Would appreciate if anyone can chip in.

      D run-out 2 Replies Last reply Reply Quote 0
      • D
        davidavr @jacksonX last edited by

        @jacksonx I would think you could create an Analyzer to do this. It has access to the strategy, and therefore all the lines within it, so you could calculate on each day your margin requirement and then at the end of the analysis, sum up the total margin cost. You would need to incorporate that into your net P&L, though.

        They other approach would be a custom broker (derived from the standard BackBroker) that only overrides the commission calculations, but that might be more work as it doesn't appear that brokers were designed to be as easily extensible as some of the other classes.

        J 1 Reply Last reply Reply Quote 0
        • J
          jacksonX @davidavr last edited by

          @davidavr thank you for your reply! I thought of using Analyser/Observer to do this. You can check your margin post-backtesting. However, you won't get notified if you're out of cash.

          Another way around this that I can think of is that, you create a synthetic asset (let's call it 'fake_margin') with OHLC all equal to 1 at all times and enormous volume. Then at each 'next()' in your strategy, you adjust the position of your fake_margin according to your options' positions. (of course you set zero commission fee for fake_margin). This way it will take up the cash part to represent your margin.

          It can do what I what backtrader to do for my covered call strategy. However, it is just...cumbersome, not elegant.

          Also, very true, would be great if I'm proficient in backtrader enough to be able to customise my own broker. Unfortunately, I'm rather new to the community. Would be great if someone can help me kick-off the process!

          Any comments, ideas, suggestions are very appreciated!

          J.X.

          1 Reply Last reply Reply Quote 0
          • run-out
            run-out @jacksonX last edited by

            @jacksonx I'm really interested in this question. But I don't feel I understand it well enough to provide a thorough answer. Do you think you could walk me through a concrete example highlighting expected results and what is currently happening?

            I think I would like to dive deep into this but would like to be on firm footing before I do.

            Thanks.

            RunBacktest.com

            1 Reply Last reply Reply Quote 0
            • J
              jaezilla last edited by

              Definitely not efficient, but I manually do it by saving all the trades and then iterating through them in post processing:

               def notify_trade(self,trade):
                      self.trades.setdefault(self.data._name, [] ).append(trade)
              
              trades_dict:dict = {}
              for trade in result.trades.get(symbol, []):
              
                  if trade.status == 1:
              
                      trades_dict[trade.baropen] = {'open': {'size': trade.size, 'price': trade.price, 'value': trade.value } }
              
                  elif trade.status == 2:
                      size = trades_dict.get(trade.baropen).get('open').get('size')
                      open_price = trades_dict.get(trade.baropen).get('open').get('price')
                      open_value = trades_dict.get(trade.baropen).get('open').get('value')
                      close_value = open_value + trade.pnl
                      close_price = close_value / size
              
                      open_commission =  min ( max (min_commision, (size * commission_rate_per_share) ), ( max_commision_pct *  size * open_price  ) ) 
                      close_commission = min ( max (min_commision, (size * commission_rate_per_share) ), ( max_commision_pct *  close_value  ) ) 
                      close_fee = close_value * trns_fee_pct
                      close_fee += min ( (size * finra_sell_fee_per_share) , finra_max_fee_amount)
              

              Interactive Brokers has a size based commission with a min and max limit. There is also a value based fee assessed on closing a position. This only works with opening and closing a position in its entirety.

              J 1 Reply Last reply Reply Quote 0
              • J
                jacksonX last edited by

                @run-out Hi, thank you very much for the reply.

                Let me try to explain what my story is here, and please correct me if I'm wrong with my understanding of bt:

                From my understanding, bt recognises 'stocklike' and 'futurelike' assets and treats them differently, i.e., trade 'on-margin' or not, when managing their transaction, and 'cash-value' of the portfolio.

                At the moment you buy or sell a futurelike asset, you have a reduction in cash since you need margin for both long and short positions, and the value of your position is recorded as a positive value in 'pos_value_unlevered ', which gets its value from the margin. When holding a position in a futurelike asset, bt 'marks-to-market' at every bar so that the pnl from holding the position shows up in 'cash' (considering multiplier and leverage) and the 'pos_value_unlevered ' is locked as the amount of margin requirement from the moment the position is being created. When closing such a position, you close at the 'open price' (position.price), and the value is refunded back to your cash. PS: I also found a bug in bt in the cash-value calculation in this setup, which was discovered and solved in an earlier thread.

                Basically, for future-like instruments:

                Δ_margin = 0
                Δ_cash = absolute_pnl
                where, Δ_margin =Δ_pos_value, and absolute_pnl = Δ_price*size*mult
                

                This is a reasonable setup for futures, although from where I trade, there are other complications (commission rules are vastly different for positions from yesterday and positions opened/closed today). But this is another topic. I'll open a new thread on this soon.

                For stock-like instruments, things are straight forward: you simply record and update the true value of your position and deduct/add cash from your account at the moment you complete a transaction.

                For options, the rules are much more complicated.

                Options 1) trade on margin (dynamically calculated) when you short; and 2) have multipliers. They behave neither future-like nor stock-like, but a bit of both.

                When you sell an option, you record a negative pos_value and you receive option premium in cash of equal amount (this is a stock-like behaviour). This cash, although added to your account, is not available to you, until the option expires or you close your position. When holding a short position in in-the-money options, you are required a margin (this is a future-like behaviour). This margin does not represent equal your pos_value_unlevered (as apposed to what bt does), it's simply the amount of cash frozen by your broker. The value of your position shall be updated at every new bar, but your total cash does not change (if you don't trade). The available cash on the other hand is updated at every bar according to the margin change.

                So when you have option shorts, your broker.value() should return (available_cash + margin + unrealised_PnL + pos_value). This is similar to what bt is doing now with futures, except 1) pos_value is negative for short positions, 2) you have unrealisedPnL recorded as cash, 3)margin is dynamically updated according to some complicated rule, 4) the sum of the available_cash, margin and unrealised_PnL does not change if you don't trade 4) and pos_value changes.

                When you buy an option, you should record a positive position value and you have your cash deducted. You also don't have margin requirement. So buying an option is just like buying a stock, only with a multiplier.

                basically, what I need bt to do now for option commission setup is to

                1. know whether you are opening or closing a position
                2. know whether you have a long or short position
                3. know meta info on this option, i.e. put/call type
                4. know some time-series variables calculated dynamically according to the bar data of the options AND the underlying asset

                What I'm doing now is by-passing all the above complications with a stock-like setup and calculating the margin in strategy and feeding the value to a customised observer so I can plot and analyse it post-backtesting. This can do the job, but not realistic or ideal.

                I know this is a lot of words. Please let me know if you have any questions so we can discuss further.

                A lot of work is needed to make backtrader option-friendly. This is only a beginning. But for sure this is an interesting project.

                1 Reply Last reply Reply Quote 0
                • J
                  jacksonX @jaezilla last edited by

                  @jaezilla Hi thanks for your reply! I have taken a similar approach. I calculate the values in strategy and then record them in an customised observer. However, doing so doesn't record the margin on the fly, so you might be making trades when you actually have insufficient funds.

                  This however does have an upside, in my opinion. It gives you more freedom when you test out strategies. You can simply check if you've been margin-called post-backtesting and estimate the amount of leverage you have left with your margins, instead of discovering on the fly that your strategy is constraint by your margin.

                  1 Reply Last reply Reply Quote 0
                  • 1 / 1
                  • First post
                    Last post
                  Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors