Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. kausality
    K
    • Flag Profile
    • Block User
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups
    Save
    Saving

    kausality

    @kausality

    7
    Reputation
    26
    Posts
    337
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    kausality Follow

    Posts made by kausality

    • A way to add next_orderbook

      We have the next() which works with updates on upcoming/next data bars, which works with OHLC or bid/ask.

      Is there a way I can add a next_orderbook() (say), to push changes in the order book so that the strategy can operate on it?

      posted in General Discussion
      K
      kausality
    • RE: Closed trade list (including MFE/MAE) analyzer

      @ab_trader
      Yes, the issue was because of exactbars=True being set. I turned that off and it worked.

      posted in Indicators/Strategies/Analyzers
      K
      kausality
    • RE: Position analyzer with entry/exit details

      Awesome work there!
      I don't need to add anything.

      I am currently doing some live bot like trading and therefore I though adding a continuous dump feature would be helpful.
      This little modification also allows one to dump the position details in a CSV file

      class trade_list(bt.Analyzer):
          params = (
              ("continuous", False),
              ("fname", "position_{0}.csv".format(time.strftime("%Y%m%d-%H%M%S"))),
              ("dump", True)
          )
          
          def __init__(self):
              self.trades = []
              self.cumprofit = 0.0
              
          def get_analysis(self):
              return self.trades
          
          def _write_to_file(self):
              if not self.p.dump:
                  return
              df = pd.DataFrame(self.trades)
              df.to_csv(self.p.fname, index=False)
      
          def notify_trade(self, trade):
              if trade.isclosed:
                  brokervalue = self.strategy.broker.getvalue()
                  dir = "short"
                  if trade.history[0].event.size > 0:
                      dir = "long"
                  pricein = trade.history[len(trade.history)-1].status.price
                  priceout = trade.history[len(trade.history)-1].event.price
                  datein = bt.num2date(trade.history[0].status.dt)
                  dateout = bt.num2date(trade.history[len(trade.history)-1].status.dt)
                  if trade.data._timeframe >= bt.TimeFrame.Days:
                      datein = datein.date()
                      dateout = dateout.date()
      
                  pcntchange = 100 * priceout / pricein - 100
                  pnl = trade.history[len(trade.history)-1].status.pnlcomm
                  pnlpcnt = 100 * pnl / brokervalue
                  barlen = trade.history[len(trade.history)-1].status.barlen
                  pbar = pnl / barlen
                  self.cumprofit += pnl
      
                  size = value = 0.0
                  for record in trade.history:
                      if abs(size) < abs(record.status.size):
                          size = record.status.size
                          value = record.status.value
      
                  highest_in_trade = max(trade.data.high.get(ago=0, size=barlen+1))
                  lowest_in_trade = min(trade.data.low.get(ago=0, size=barlen+1))
                  hp = 100 * (highest_in_trade - pricein) / pricein
                  lp = 100 * (lowest_in_trade - pricein) / pricein
                  if dir == "long":
                      mfe = hp
                      mae = lp
                  else:
                      mfe = -lp
                      mae = -hp
      
                  self.trades.append({"ref": trade.ref, "ticker": trade.data._name, "dir": dir,
                                      "datein": datein, "pricein": pricein, "dateout": dateout, "priceout": priceout,
                                      "chng%": round(pcntchange, 2), "pnl": pnl, "pnl%": round(pnlpcnt, 2),
                                      "size": size, "value": value, "cumpnl": self.cumprofit,
                                      "nbars": barlen, "pnl/bar": round(pbar, 2),
                                      "mfe%": round(mfe, 2), "mae%": round(mae, 2)})
                  if self.p.continuous:
                      self._write_to_file()
      
          def stop(self):
              if not self.p.continuous:
                  self._write_to_file()
      
      
      posted in General Discussion
      K
      kausality
    • RE: Multiple Live Data Feeds

      @totoro It depends on what you are doing inside the loop. If you are making some calculations like std devs, atr etc then I don't think that even with 100's of data feed your lag could reach 10s. If you are running some neural network based complex calculations then it can though.
      You can use something like the time command to get an idea about your execution time.

      posted in General Discussion
      K
      kausality
    • RE: Multiple Live Data Feeds

      @totoro You would have to process each data feed separately and there is no workaround that in any language or using any framework. Even using pandas you have to filter the DataFrame according to the symbol being processed in this round.

      If your strategy relies on microseconds precision then you are entering the realm of HFT and in that case, you have to evaluate if Python is really the correct tool of your choice.

      posted in General Discussion
      K
      kausality
    • RE: Closed trade list (including MFE/MAE) analyzer

      @ab_trader
      I am testing this on a live bot.

      I ran into the following issue:

      [TradeHistory([('status', AutoOrderedDict([('status', 1), ('dt', 736955.651388889), ('barlen', 0), ('size', 46), ('price', 6338.0), ('value', 291548.0), ('pnl', 0.0), ('pnlcomm', 0.0), ('tz', None)])), ('event', AutoOrderedDict([('order', <backtrader.order.BuyOrder object at 0x112DBA70>), ('size', 46), ('price', 6338), ('commission', 0.0)]))]), TradeHistory([('status', AutoOrderedDict([('status', 2), ('dt', 736955.7006944445), ('barlen', 71), ('size', 0), ('price', 6338.0), ('value', 0.0), ('pnl', 506.0), ('pnlcomm', 506.0), ('tz', None)])), ('event', AutoOrderedDict([('order', <backtrader.order.SellOrder object at 0x132FBB30>), ('size', -46), ('price', 6349), ('commission', 0.0)]))])] ref:1
      data:<backmex.feed.BitMEXData object at 0x1129C5F0>
      tradeid:0
      size:0
      price:6338.0
      value:0.0
      commission:0.0
      pnl:506.0
      pnlcomm:506.0
      justopened:False
      isopen:False
      isclosed:True
      baropen:101
      dtopen:736955.651388889
      barclose:172
      dtclose:736955.7006944445
      barlen:71
      historyon:True
      history:[TradeHistory([('status', AutoOrderedDict([('status', 1), ('dt', 736955.651388889), ('barlen', 0), ('size', 46), ('price', 6338.0), ('value', 291548.0), ('pnl', 0.0), ('pnlcomm', 0.0), ('tz', None)])), ('event', AutoOrderedDict([('order', <backtrader.order.BuyOrder object at 0x112DBA70>), ('size', 46), ('price', 6338), ('commission', 0.0)]))]), TradeHistory([('status', AutoOrderedDict([('status', 2), ('dt', 736955.7006944445), ('barlen', 71), ('size', 0), ('price', 6338.0), ('value', 0.0), ('pnl', 506.0), ('pnlcomm', 506.0), ('tz', None)])), ('event', AutoOrderedDict([('order', <backtrader.order.SellOrder object at 0x132FBB30>), ('size', -46), ('price', 6349), ('commission', 0.0)]))])]
      status:2
      
        self._runnext(runstrats)
        File "D:\envs\twenv\lib\site-packages\backtrader\cerebro.py", line 1623, in _runnext
          self._brokernotify()
        File "D:\envs\twenv\lib\site-packages\backtrader\cerebro.py", line 1370, in _brokernotify
          owner._addnotification(order, quicknotify=self.p.quicknotify)
        File "D:\envs\twenv\lib\site-packages\backtrader\strategy.py", line 553, in _addnotification
          self._notify(qorders=qorders, qtrades=qtrades)
        File "D:\envs\twenv\lib\site-packages\backtrader\strategy.py", line 577, in _notify
          analyzer._notify_trade(trade)
        File "D:\envs\twenv\lib\site-packages\backtrader\analyzer.py", line 170, in _notify_trade
          self.notify_trade(trade)
        File "D:\envs\twenv\tradework\lib\backtrader\helpers.py", line 168, in notify_trade
          highest_in_trade = max(trade.data.high.get(ago=0, size=barlen+1))
        File "D:\envs\twenv\lib\site-packages\backtrader\linebuffer.py", line 182, in get
          return list(islice(self.array, start, end))
      ValueError: Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize.
      

      The first two objects are the printout of 'trade' and 'trade.history', if it helps in finding the issue.

      EDIT: I am using this with exactbars=True option in cerebro and maybe this is causing the error. I will try the same with this option off and let it be known here.

      posted in Indicators/Strategies/Analyzers
      K
      kausality
    • RE: Closing trade on the same day

      EDIT: Post created by mistake. As I cannot delete it, I have edited it out.

      posted in General Discussion
      K
      kausality
    • RE: Position analyzer with entry/exit details

      @ab_trader
      Thanks for the comments. This is a good use case and I will be thinking of how to add this.

      posted in General Discussion
      K
      kausality
    • Position analyzer with entry/exit details

      Sometimes during backtesting, we may want to know the timings of entry/exit along with other position details so we can verify it with real data.
      This is even more imperative when the strategy is being used to generate signals on T - 1 day and then later confirmed in the market how it would have performed on day T.

      I have written a little utility(Analyzer) which outputs all these details in a CSV file. Hope this is useful.

      import time
      import queue
      import pandas as pd
      import backtrader as bt
      from collections import defaultdict
      
      class PositionAnalyzer(bt.Analyzer):
          params = (
              ("continuous", False),
              ("fname", "position_{0}.csv".format(time.strftime("%Y%m%d-%H%M%S")))
          )
      
          def __init__(self):
              super(PositionAnalyzer, self).__init__()
              self.order_map = defaultdict(queue.Queue)
              self.df = pd.DataFrame(columns=["instrument", "entry_dt", "exit_dt", "size", "value",
                                              "direction", "entry_price", "exit_price", "pnl", "pnl_comm"])
      
          def notify_order(self, order):
              if not order.status == order.Completed:
                  return
              self.order_map[order.data].put(order)
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
              entry_order = self.order_map[trade.data].get()
              exit_order = self.order_map[trade.data].get()
              instrument = trade.data._dataname
              entry_dt = bt.num2date(entry_order.executed.dt)
              exit_dt = bt.num2date(exit_order.executed.dt)
              size = entry_order.executed.size
              value = entry_order.executed.size * entry_order.executed.price
              direction = "BUY" if entry_order.isbuy() else "SELL"
              entry_price = entry_order.executed.price
              exit_price = exit_order.executed.price
              pnl = round(trade.pnl, 2)
              pnl_comm = round(trade.pnlcomm, 2)
              self.df.loc[len(self.df)] = [instrument, entry_dt, exit_dt, size, value,
                                           direction, entry_price, exit_price, pnl, pnl_comm]
              if self.p.continuous:
                  self.df.to_csv(self.p.fname, index=False)
      
          def stop(self):
              if not self.p.continuous:
                  self.df.to_csv(self.p.fname, index=False)
      
          def get_analysis(self):
              return self.df
      

      Example of a generated output:

      instrument,entry_dt,exit_dt,size,value,direction,entry_price,exit_price,pnl,pnl_comm
      ADANIPORTS,2018-05-22 05:30:00,2018-05-22 05:30:00,-1,-381.5,SELL,381.5,381.35,0.15,0.15
      ADANIPORTS,2018-05-23 05:30:00,2018-05-23 05:30:00,-1,-377.75,SELL,377.75,374.05,3.7,3.7
      ADANIPORTS,2018-05-24 05:30:00,2018-05-24 05:30:00,-1,-373.75,SELL,373.75,371.5,2.25,2.25
      ADANIPORTS,2018-06-07 05:30:00,2018-06-07 05:30:00,1,378.0,BUY,378.0,381.0,3.0,3.0
      ADANIPORTS,2018-06-14 05:30:00,2018-06-14 05:30:00,-1,-381.65,SELL,381.65,374.6,7.05,7.05
      ADANIPORTS,2018-06-15 05:30:00,2018-06-15 05:30:00,-1,-371.3,SELL,371.3,371.65,-0.35,-0.35
      ADANIPORTS,2018-06-21 05:30:00,2018-06-21 05:30:00,1,369.6,BUY,369.6,366.5,-3.1,-3.1
      
      posted in General Discussion
      K
      kausality
    • RE: Closing trade on the same day

      I am saving reference to open positions in the stocks using a dictionary which maps 'data' to True/False denoting open positions.

      At the start of next(), I close all the positions in 'data' which have open positions using the above dict.

          def next(self):
              for d in self.pos_map:
                  if self.pos_map[d]:
                      self.close(data=d)
                      self.pos_map[d] = False
              # more code to create orders using strategy
      

      I hope I am doing it right and it will close the orders at the close which were executed in the last next() cycle(the bar after whose completion this next() was called and in which my main orders were executed)

      posted in General Discussion
      K
      kausality
    • 1
    • 2
    • 3
    • 1 / 3