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/

    Flipping a position from long to short

    General Code/Help
    4
    32
    3234
    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.
    • M
      marketwizard @run-out last edited by

      @run-out said I tried with your piece of code, however, I received an error:

      Traceback (most recent call last):
        File "C:/Users/marketwizard/PycharmProjects/MW_Backtests/01_WSTF_EMA_Crossover_50_200_Flip_LongShort/main.py", line 406, in <module>
          strategies = cerebro.run(tradehistory=True)
        File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\cerebro.py", line 1127, in run
          runstrat = self.runstrategies(iterstrat)
        File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\cerebro.py", line 1301, in runstrategies
          strat._stop()
        File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\strategy.py", line 486, in _stop
          analyzer._stop()
        File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\analyzer.py", line 200, in _stop
          self.stop()
        File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\analyzers\vwr.py", line 154, in stop
          dt = pn / (pi * math.exp(ravg * n)) - 1.0
      ZeroDivisionError: float division by zero
      

      (compared to the code I had posted in the previous messages, I added some analyzers. I know this part is working well because I use it often with other strategies without problems)

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

        @run-out I analyzed my problem a bit more and it seems that with the code you recommended to use in next(), no trade is executed.

            def next(self):
        
                if self.order:
                    return  # pending order execution
        
                if self.cross > 0.0 and self.getposition().size <= 0:
                    self.order = self.order_target_percent(target=self.p.percent)
        
                elif self.cross < 0.0 and self.getposition().size >= 0:
                    self.order = self.order_target_percent(target=-self.p.percent)
        

        Maybe someone can help to solve the problem ?

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

          @marketwizard

          I copied your code and ran it locally. It seems to be working. You have a long period for ema, just make sure your data covers this many periods. I shortened it for mine. Below is your code, I removed some of the logs and printouts.

          import backtrader as bt
          import pandas as pd
          import os.path
          import sys
          from datetime import datetime, timedelta, date
          import itertools
          from csv import reader
          import csv
          import math
          
          period = 7305
          icap = 100000
          
          
          strategy_name = "EMA_CrossOver_50_200_Flip_LongShort"
          
          
          class EMAStack(bt.Strategy):
              # Define the parameters of the strategy
              params = (
                  ("portfolio_expo", 0.98),  # Max 15% of the Portfolio per trade
                  ("trade_risk", 0.02),  # Max 2% risk per trade (stop loss)
                  ("atrdist", 2.0),  # ATR based Stop loss distance
                  ("stake", 1.00),
                  ("mtrade", False),
                  ("percent", .5)
              )
          
              # Initialize the elements which are needed for the strategy (indicators, etc...)
              def __init__(self):
                  self.order = None  # sentinel to avoid operations on pending order
          
                  # Define the indicators
                  self.ema_fast = bt.indicators.EMA(
                      self.data.close, period=5, plot=True, subplot=False
                  )
          
                  self.ema_slow = bt.indicators.EMA(
                      self.data.close, period=20, plot=True, subplot=False
                  )
          
                  self.atr = bt.indicators.ATR(period=14, plot=False, subplot=False)
          
                  # Define the crossover signals
                  self.cross = bt.indicators.CrossOver(
                      self.ema_fast, self.ema_slow, plot=False, subplot=False
                  )
          
                  if self.p.mtrade:
                      self.tradeid = itertools.cycle([0, 1, 2])
                  else:
                      self.tradeid = itertools.cycle([0])
          
              def next(self):
          
                  # Get the Amount of cash in the Portfolio
                  cash = self.broker.get_cash()
                  brokervalue = self.broker.get_value()
          
                  if self.order:
                      return  # pending order execution
          
                  if self.cross > 0.0 and self.getposition().size <= 0:
                      self.order = self.order_target_percent(target=self.p.percent)
                  elif self.cross < 0.0 and self.getposition().size >= 0:
                      self.order = self.order_target_percent(target=-self.p.percent)
          
          
                  print(
                      "next(): Cash: {}, Broker Value: {}, Fast EMA: {}, Slow EMA: {}, CrossOver: {}".format(
                          round(cash, 2),
                          round(brokervalue, 2),
                          round(self.ema_fast[0], 2),
                          round(self.ema_slow[0], 2),
                          round(self.cross[0], 2),
                      )
                  )
          
              def notify_order(self, order):
          
                  if order.status == order.Completed:
                      pass
          
                  if not order.alive():
                      self.order = None  # indicate no order is pendin
          
                  date = self.data.datetime.datetime().date()
          
                  if order.status == order.Accepted:
                      print("-" * 32, " NOTIFY ORDER ", "-" * 32)
                      print("{} Order Accepted".format(order.info["name"]))
                      print(
                          "{}, Status {}: Ref: {}, Size: {}, Price: {}".format(
                              date,
                              order.status,
                              order.ref,
                              order.size,
                              "NA" if not order.price else round(order.price, 5),
                          )
                      )
          
                  if order.status == order.Completed:
                      print("-" * 32, " NOTIFY ORDER ", "-" * 32)
                      print("{} Order Completed".format(order.info["name"]))
                      print(
                          "{}, Status {}: Ref: {}, Size: {}, Price: {}".format(
                              date,
                              order.status,
                              order.ref,
                              order.size,
                              "NA" if not order.price else round(order.price, 5),
                          )
                      )
                      print(
                          "Created: {} Price: {} Size: {}".format(
                              bt.num2date(order.created.dt),
                              order.created.price,
                              order.created.size,
                          )
                      )
                      print("-" * 80)
          
                  if order.status == order.Canceled:
                      print("-" * 32, " NOTIFY ORDER ", "-" * 32)
                      print("{} Order Canceled".format(order.info["name"]))
                      print(
                          "{}, Status {}: Ref: {}, Size: {}, Price: {}".format(
                              date,
                              order.status,
                              order.ref,
                              order.size,
                              "NA" if not order.price else round(order.price, 5),
                          )
                      )
          
                  if order.status == order.Rejected:
                      print("-" * 32, " NOTIFY ORDER ", "-" * 32)
                      print("WARNING! {} Order Rejected".format(order.info["name"]))
                      print(
                          "{}, Status {}: Ref: {}, Size: {}, Price: {}".format(
                              date,
                              order.status,
                              order.ref,
                              order.size,
                              "NA" if not order.price else round(order.price, 5),
                          )
                      )
                      print("-" * 80)
          
              def notify_trade(self, trade):
                  date = self.data.datetime.datetime()
                  if trade.isclosed:
                      print("-" * 32, " NOTIFY TRADE ", "-" * 32)
                      print(
                          "{}, Close Price: {}, Profit, Gross {}, Net {}".format(
                              date, trade.price, round(trade.pnl, 2), round(trade.pnlcomm, 2)
                          )
                      )
                      print("-" * 80)
          
          
          if __name__ == "__main__":
          
          
              cerebro = bt.Cerebro()
          
              tickers = ["FB", "MSFT"]
              for ticker in tickers:
                  data = bt.feeds.YahooFinanceData(
                      dataname=ticker,
                      timeframe=bt.TimeFrame.Days,
                      fromdate=datetime(2020, 9, 1),
                      todate=datetime(2020, 12, 1),
                      reverse=False,
                  )
          
          
                  cerebro.adddata(data, name=ticker)
          
          
              # Set the Cash for the Strategy
              cerebro.broker.setcash(icap)
          
              # Set the comissions
              cerebro.broker.setcommission(commission=0.005)
          
              cerebro.addstrategy(EMAStack)
          
              cerebro.addsizer(bt.sizers.AllInSizer)
          
              cerebro.broker.set_checksubmit(checksubmit=False)
          
              # Run over everything
              strategies = cerebro.run(tradehistory=True)
              # strategies = cerebro.run()
              # Sta = strategies[0]
          
          

          RunBacktest.com

          M 1 Reply Last reply Reply Quote 2
          • M
            marketwizard @run-out last edited by

            @run-out Thank you for your reply. I tested your code (with the same parameters) and now it works !

            With 50% of the portfolio no problem, however when I try to go all-in, the results are a bit strange.
            Some short trades are taken in a row without going long inbetween. Here is a screenshot of the tradelist I generated:

            Backtrader community.JPG

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

              @marketwizard You're hitting margin or lack of cash. Do your short sales first if possible, leave a buffer of cash. I usually use 2.5% or so.

              RunBacktest.com

              M 1 Reply Last reply Reply Quote 2
              • M
                marketwizard @run-out last edited by

                @run-out If I understand that well, setting self.p.percent to 0.975 should provide enough cash buffer for the backtests ?

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

                  @marketwizard Probably yes.

                  RunBacktest.com

                  M 1 Reply Last reply Reply Quote 2
                  • M
                    marketwizard @run-out last edited by

                    @run-out The problem remain until I reduce the percentage to approx. 0.92.

                    Does other solution exists in order to avoid this Problem ? (beside reducing the position size) in order to go all in

                    run-out A 2 Replies Last reply Reply Quote 0
                    • run-out
                      run-out @marketwizard last edited by

                      @marketwizard Check out leverage. https://community.backtrader.com/topic/118/leverage-discussion

                      RunBacktest.com

                      1 Reply Last reply Reply Quote 1
                      • A
                        ab_trader @marketwizard last edited by

                        @marketwizard Try cheat-on-open feature. In this case open price will be known and size can be calculated close to 100%.

                        • If my answer helped, hit reputation up arrow at lower right corner of the post.
                        • Python Debugging With Pdb
                        • New to python and bt - check this out
                        M 1 Reply Last reply Reply Quote 2
                        • M
                          marketwizard @ab_trader last edited by

                          @ab_trader I tried with cheat on open and the same problems seems to occure (2 shorts in a row, etc... The order is accepted, completed but the trade is not executed).

                          class EMAStack(bt.Strategy):
                              # Define the parameters of the strategy
                              params = (
                                  ("stake", 1.00),
                                  ("mtrade", False),
                                  ("percent", 0.99)
                              )
                          
                              # Initialize the elements which are needed for the strategy (indicators, etc...)
                              def __init__(self):
                                  self.order = None  # sentinel to avoid operations on pending order
                                  self.cheating = self.cerebro.p.cheat_on_open
                          
                                  # Define the indicators
                                  self.ema_fast = bt.indicators.EMA(
                                      self.data.close, period=5, plot=True, subplot=False
                                  )
                          
                                  self.ema_slow = bt.indicators.EMA(
                                      self.data.close, period=20, plot=True, subplot=False
                                  )
                          
                                  # Define the crossover signals
                                  self.cross = bt.indicators.CrossOver(
                                      self.ema_fast, self.ema_slow, plot=False, subplot=False
                                  )
                          
                                  if self.p.mtrade:
                                      self.tradeid = itertools.cycle([0, 1, 2])
                                  else:
                                      self.tradeid = itertools.cycle([0])
                          
                              def operate(self, fromopen):
                                  if self.order is not None:
                                      return
                          
                                  if self.cross > 0.0:
                                      self.order = self.order_target_percent(target=self.p.percent)
                          
                                  elif self.cross < 0.0:
                                      self.order = self.order_target_percent(target=-self.p.percent)
                          
                              def prenext(self):
                                  cash = self.broker.get_cash()
                                  brokervalue = self.broker.get_value()
                                  print('Prenext(): Cash: {}, Broker Value: {}, Fast EMA: {}, Slow EMA: {}, CrossOver: {}'.format(round(cash, 2), round(brokervalue, 2), round(self.ema_fast[0], 2), round(self.ema_slow[0], 2), round(self.cross[0], 2)))
                                  self.next()
                          
                              def next(self):
                          
                                  # Get the Amount of cash in the Portfolio
                                  cash = self.broker.get_cash()
                                  brokervalue = self.broker.get_value()
                                  data_value = self.broker.get_value([self.data])
                          
                                  if self.cheating:
                                      return
                                  self.operate(fromopen=False)
                          
                                  #if self.order:
                                   #   return  # pending order execution
                          
                                  print('next(): Cash: {}, Broker Value: {}, Fast EMA: {}, Slow EMA: {}, CrossOver: {}'.format(round(cash, 2),
                                                                                                                   round(brokervalue, 2),
                                                                                                                   round(self.ema_fast[0], 2),
                                                                                                                   round(self.ema_slow[0], 2),
                                                                                                                   round(self.cross[0], 2)))
                              def next_open(self):
                                  if not self.cheating:
                                      return
                                  self.operate(fromopen=True)
                          
                              def notify_order(self, order):
                          
                                  if order.status == order.Completed:
                                      pass
                          
                                  if not order.alive():
                                      self.order = None  # indicate no order is pendin
                          
                                  date = self.data.datetime.datetime().date()
                          
                                  if order.status == order.Accepted:
                                      print('-'*32,' NOTIFY ORDER ','-'*32)
                                      print('{} Order Accepted'.format(order.info['name']))
                                      print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                                                                                  date,
                                                                                  order.status,
                                                                                  order.ref,
                                                                                  order.size,
                                                                                  'NA' if not order.price else round(order.price,5)
                                                                                  ))
                          
                          
                                  if order.status == order.Completed:
                                      print('-'*32,' NOTIFY ORDER ','-'*32)
                                      print('{} Order Completed'.format(order.info['name']))
                                      print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                                                                                  date,
                                                                                  order.status,
                                                                                  order.ref,
                                                                                  order.size,
                                                                                  'NA' if not order.price else round(order.price,5)
                                                                                  ))
                                      print('Created: {} Price: {} Size: {}'.format(bt.num2date(order.created.dt), order.created.price,order.created.size))
                                      print('-'*80)
                          
                                  if order.status == order.Canceled:
                                      print('-'*32,' NOTIFY ORDER ','-'*32)
                                      print('{} Order Canceled'.format(order.info['name']))
                                      print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                                                                                  date,
                                                                                  order.status,
                                                                                  order.ref,
                                                                                  order.size,
                                                                                  'NA' if not order.price else round(order.price,5)
                                                                                  ))
                          
                                  if order.status == order.Rejected:
                                      print('-'*32,' NOTIFY ORDER ','-'*32)
                                      print('WARNING! {} Order Rejected'.format(order.info['name']))
                                      print('{}, Status {}: Ref: {}, Size: {}, Price: {}'.format(
                                                                                  date,
                                                                                  order.status,
                                                                                  order.ref,
                                                                                  order.size,
                                                                                  'NA' if not order.price else round(order.price,5)
                                                                                  ))
                                      print('-'*80)
                          
                              def notify_trade(self, trade):
                                  date = self.data.datetime.datetime()
                                  if trade.isclosed:
                                      print('-'*32,' NOTIFY TRADE ','-'*32)
                                      print('{}, Close Price: {}, Profit, Gross {}, Net {}'.format(
                                                                          date,
                                                                          trade.price,
                                                                          round(trade.pnl,2),
                                                                          round(trade.pnlcomm,2)))
                                      print('-'*80)
                          
                          
                          
                          
                          run-out 1 Reply Last reply Reply Quote 0
                          • run-out
                            run-out @marketwizard last edited by

                            @marketwizard Do an experiment and reduce your percet to something low, like 0.75. If your algo works this means you are too close to margin for the volatility in your stocks.

                            RunBacktest.com

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