Flipping a position from long to short
-
Hello all,
I tried to flip the positions in my strategy from long to short.
The code is running but the backtest results are a bit strange.
In fact, most of the time, the program take only one trade (or sometimes 2, depending on the asset) over the last 20 years (daily timeframe).Maybe someone faced the same problem in the past ?
class EMAStack(bt.Strategy): # Define the parameters of the strategy params = ( ('portfolio_expo', 0.98), ('trade_risk', 0.02), # Max 2% risk per trade (stop loss) ('atrdist', 2.0) # ATR based Stop loss distance ) def notify_order(self, order): if order.status == order.Completed: pass if not order.alive(): self.order = None # indicate no order is pending # Initialize the elements which are needed for the strategy (indicators, etc...) def __init__(self): # Define the indicators self.ema_fast = bt.indicators.EMA(self.data.close, period=50, plot=True, subplot=False) self.ema_slow = bt.indicators.EMA(self.data.close, period=200, plot=True, subplot=False) self.atr = bt.indicators.ATR(period=14, plot=False, subplot=False) # Define the crossover signals self.bull_cross = bt.indicators.CrossOver(self.ema_fast, self.ema_slow, plot=False, subplot=False) self.bear_cross = bt.indicators.CrossOver(self.ema_slow, self.ema_fast, plot=False, subplot=False) def start(self): self.order = None # sentinel to avoid operations on pending order def prenext(self): self.next() def next(self): # Get the Amount of cash in the Portfolio cash = self.broker.get_cash() if self.order: return # pending order execution if self.bull_cross > 0.0: # Calculation of the Stock Qty to buy depending on our risk strategy # calculate the absolute stop loss distance with atr pdist = self.atr[0] * self.p.atrdist # calculate the stop price self.pstop = self.data.close[0] - pdist # calculate the amount of shares to buy / sell depending on the stop loss and the risk strategy qty = math.floor((cash * self.p.trade_risk) / pdist) # calculate the maximum exposure depending on the risk strategy portfolio_exposure_calc = qty * self.data.close[0] portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) self.order = self.buy(size=qty) if self.bear_cross > 0.0: # Calculation of the Stock Qty to buy depending on our risk strategy # calculate the absolute stop loss distance with atr pdist = self.atr[0] * self.p.atrdist # calculate the stop price self.pstop = self.data.close[0] - pdist # calculate the amount of shares to buy / sell depending on the stop loss and the risk strategy qty = math.floor((cash * self.p.trade_risk) / pdist) # calculate the maximum exposure depending on the risk strategy portfolio_exposure_calc = qty * self.data.close[0] portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) self.order = self.sell(size=qty)
Cheers
Marketwizard -
Position size is defined based on cash available. After you open the first position there is not enough cash for 2nd order and its size is zero.
-
@marketwizard if you close an open position before issuing a new trade, it will work as expected. Here's an example of a crossover strategy that buys and sells on crossover direction https://github.com/mementum/backtrader/blob/master/samples/multitrades/multitrades.py#L75:L92
if self.signal > 0.0: # cross upwards if self.position: self.log('CLOSE SHORT , %.2f' % self.data.close[0]) self.close(tradeid=self.curtradeid) self.log('BUY CREATE , %.2f' % self.data.close[0]) self.curtradeid = next(self.tradeid) self.buy(size=self.p.stake, tradeid=self.curtradeid) elif self.signal < 0.0: if self.position: self.log('CLOSE LONG , %.2f' % self.data.close[0]) self.close(tradeid=self.curtradeid) if not self.p.onlylong: self.log('SELL CREATE , %.2f' % self.data.close[0]) self.curtradeid = next(self.tradeid) self.sell(size=self.p.stake, tradeid=self.curtradeid)
-
@ab_trader I tried to reduce the position size to 50%, however I still have the same problem
-
@crazy25000 Thank for sharing your code.
I modified it a bit, in order to be able to go "all-in" on the long and the short side.
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) ) def notify_order(self, order): if order.status == order.Completed: pass if not order.alive(): self.order = None # indicate no order is pending # Initialize the elements which are needed for the strategy (indicators, etc...) def __init__(self): # Define the indicators self.ema_fast = bt.indicators.EMA(self.data.close, period=50, plot=True, subplot=False) self.ema_slow = bt.indicators.EMA(self.data.close, period=200, plot=True, subplot=False) # Define the crossover signals self.bull_cross = bt.indicators.CrossOver(self.ema_fast, self.ema_slow, plot=False, subplot=False) self.bear_cross = bt.indicators.CrossOver(self.ema_slow, self.ema_fast, plot=False, subplot=False) if self.p.mtrade: self.tradeid = itertools.cycle([0, 1, 2]) else: self.tradeid = itertools.cycle([0]) def start(self): self.order = None # sentinel to avoid operations on pending order def prenext(self): self.next() def next(self): # Get the Amount of cash in the Portfolio cash = self.broker.get_cash() if self.order: return # pending order execution if self.bull_cross > 0.0: if self.position: # Calculation of the Stock Qty to buy depending on our risk strategy self.close(tradeid=self.curtradeid) portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) #self.order = self.buy(size=qty) self.curtradeid = next(self.tradeid) #self.buy(size=self.p.stake, tradeid=self.curtradeid) self.buy(size=qty, tradeid=self.curtradeid) if self.bear_cross > 0.0: if self.position: self.close(tradeid=self.curtradeid) portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) self.curtradeid = next(self.tradeid) #self.sell(size=self.p.stake, tradeid=self.curtradeid) self.sell(size=qty, tradeid=self.curtradeid)
However, when I analyze my trades, I see that the programm only flip the position once or twice at the beginning then it keeps going short.
When a long is taken, the size following short is much smaller than the long. -
@marketwizard backtrader has builtin sizers and one of them is AllInSizer https://www.backtrader.com/docu/sizers-reference/#allinsizer There are others like fixed and percent that you could swap out with the manual calculations.
How to add sizers in the docs https://www.backtrader.com/docu/sizers/sizers/#using-sizers
Have you tried using the builtin sizers instead of manually calculating it? Should make your position sizing strategy easier to implement.
-
@marketwizard said in Flipping a position from long to short:
However, when I analyze my trades, I see that the programm only flip the position once or twice at the beginning then it keeps going short.
Recommend initializing one crossover instead of 2. It doesn't answer the question, but makes calculation and strategy simpler.
self.crossover = bt.indicators.CrossOver(self.ema_fast, self.ema_slow, plot=False, subplot=False) ..... def next(self): if self.crossover > 0: #buy elif self.crossover < 0: #sell
When a long is taken, the size following short is much smaller than the long.
You're calculating the quantity for each trade so it's expected to vary.
-
We can continue our guessing games here, but the best way to figure out what is going on in your code is to print as much information as possible. Print the following -
- broker value, cash, signal value, orders related info such as
qty
,tradeid
at eachprenext
/next
call - order statuses and
tradeid
which goes to order atnotify_order
call - trades related info at
notify_trade
call
This will help you to figure out what is going on in the script. Looking on your logic I think that you have not a lot of cash on hands when you calculate
qty
for long positions, therefore they are skipped. But this is just my guess. - broker value, cash, signal value, orders related info such as
-
@crazy25000 I tried with the sizers (cerebro.addsizer(bt.sizers.AllInSizer) the problem remains the same. At the beginning the programm switches the positions and later it only takes trades in one direction.
-
@marketwizard can you provide a minimal, reproducible example like @ab_trader mentioned? Difficult to troubleshoot why that is happening.
-
@crazy25000 I'm trying to print the informations @ab_trader mentionned, but I'm struggling a bit.
Maybe do you have a piece of code I can use ? -
@ab_trader I printed the trades in a CSV and the order in the Terminal. Here is the result:
-------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2002-01-03, Status 2: Ref: 1, Size: 27864.49008946133, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2002-06-24, Status 2: Ref: 2, Size: -38530.7192334889, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2002-06-24, Status 4: Ref: 2, Size: -38530.7192334889, Price: NA Created: 2002-06-21 23:59:59.999989 Price: 0.259533177655 Size: -38530.7192334889 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2003-05-23, Status 2: Ref: 3, Size: 38530.7192334889, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2003-05-23, Status 4: Ref: 3, Size: 38530.7192334889, Price: NA Created: 2003-05-22 23:59:59.999989 Price: 0.280942739491 Size: 38530.7192334889 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2003-05-23 23:59:59.999989, Close Price: 0.2583, Profit, Gross -855.38, Net -959.18 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2006-07-07, Status 2: Ref: 4, Size: -5262.402041686774, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2006-07-07, Status 4: Ref: 4, Size: -5262.402041686774, Price: NA Created: 2006-07-06 23:59:59.999989 Price: 1.71800181814 Size: -5262.402041686774 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2006-08-04, Status 2: Ref: 5, Size: 5262.402041686774, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2006-08-04, Status 4: Ref: 5, Size: 5262.402041686774, Price: NA Created: 2006-08-03 23:59:59.999989 Price: 2.14372864487 Size: 5262.402041686774 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2006-08-04 23:59:59.999989, Close Price: 1.7090999999999998, Profit, Gross -1875.52, Net -1974.84 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-03-03, Status 2: Ref: 6, Size: -1834.7202969781647, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-03-03, Status 4: Ref: 6, Size: -1834.7202969781647, Price: NA Created: 2008-02-29 23:59:59.999989 Price: 3.85125672052 Size: -1834.7202969781647 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-04-17, Status 2: Ref: 7, Size: 1834.7202969781647, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-04-17, Status 4: Ref: 7, Size: 1834.7202969781647, Price: NA Created: 2008-04-16 23:59:59.999989 Price: 4.73474770392 Size: 1834.7202969781647 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2008-04-17 23:59:59.999989, Close Price: 3.8334, Profit, Gross -1680.79, Net -1759.52 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-09-24, Status 2: Ref: 8, Size: -1358.079892234643, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-09-24, Status 4: Ref: 8, Size: -1358.079892234643, Price: NA Created: 2008-09-23 23:59:59.999989 Price: 3.90732204792 Size: -1358.079892234643 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2009-05-12, Status 2: Ref: 9, Size: 1358.079892234643, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2009-05-12, Status 4: Ref: 9, Size: 1358.079892234643, Price: NA Created: 2009-05-11 23:59:59.999989 Price: 3.99142003902 Size: 1358.079892234643 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2009-05-12 23:59:59.999989, Close Price: 3.9206, Profit, Gross -95.74, Net -149.47 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2012-12-21, Status 2: Ref: 10, Size: -317.99431705713874, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2012-12-21, Status 4: Ref: 10, Size: -317.99431705713874, Price: NA Created: 2012-12-20 23:59:59.999989 Price: 16.2172309168 Size: -317.99431705713874 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2013-09-10, Status 2: Ref: 11, Size: 317.99431705713874, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2013-09-10, Status 4: Ref: 11, Size: 317.99431705713874, Price: NA Created: 2013-09-09 23:59:59.999989 Price: 16.0336449151 Size: 317.99431705713874 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2013-09-10 23:59:59.999989, Close Price: 15.929399999999998, Profit, Gross -33.45, Net -84.27 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-09-08, Status 2: Ref: 12, Size: -201.31946881211454, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-09-08, Status 4: Ref: 12, Size: -201.31946881211454, Price: NA Created: 2015-09-04 23:59:59.999989 Price: 25.1973266469 Size: -201.31946881211454 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-11-24, Status 2: Ref: 13, Size: 201.31946881211454, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-11-24, Status 4: Ref: 13, Size: 201.31946881211454, Price: NA Created: 2015-11-23 23:59:59.999989 Price: 27.2695554929 Size: 201.31946881211454 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2015-11-24 23:59:59.999989, Close Price: 25.7461, Profit, Gross -287.12, Net -340.39 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-12-17, Status 2: Ref: 14, Size: -183.52956094666692, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-12-17, Status 4: Ref: 14, Size: -183.52956094666692, Price: NA Created: 2015-12-16 23:59:59.999989 Price: 25.7850726843 Size: -183.52956094666692 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2016-08-24, Status 2: Ref: 15, Size: 183.52956094666692, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2016-08-24, Status 4: Ref: 15, Size: 183.52956094666692, Price: NA Created: 2016-08-23 23:59:59.999989 Price: 25.6363355636 Size: 183.52956094666692 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2016-08-24 23:59:59.999989, Close Price: 25.942599999999995, Profit, Gross 68.53, Net 21.26 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2018-12-17, Status 2: Ref: 16, Size: -117.64482729046028, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2018-12-17, Status 4: Ref: 16, Size: -117.64482729046028, Price: NA Created: 2018-12-14 23:59:59.999989 Price: 40.4062246176 Size: -117.64482729046028 -------------------------------------------------------------------------------- -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2019-04-09, Status 2: Ref: 17, Size: 117.64482729046028, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2019-04-09, Status 4: Ref: 17, Size: 117.64482729046028, Price: NA Created: 2019-04-08 23:59:59.999989 Price: 49.0688976331 Size: 117.64482729046028 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2019-04-09 23:59:59.999989, Close Price: 40.3989, Profit, Gross -1026.32, Net -1078.98 --------------------------------------------------------------------------------
-
@marketwizard ok, first step in preparation for debugging is done. now the information from my 1st bullet point need to be printed as well as
tradeid
value need to be added to the order information. after that we can figure out what is going on in your script.when you will have all the information logged, please post the script as well to see where the log messages are generated in the code.
-
@ab_trader concerning the first bulletpoint, I tried to print: cash, order.ref, and order.size in prenext() but I received an error message:
the code:
def prenext(self): cash = self.broker.get_cash() self.next() print('Prenext: Cash: {}: , Order Ref: {}, Order Size: {}'.format(cash, order.ref, order.size))
The error:
Traceback (most recent call last): File "C:/Users/marketwizard/PycharmProjects/MW_TradingFactory_Backtests/01_WSTF_EMA_Crossover_50_200_Flip_LongShort/main.py", line 431, 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 1293, in runstrategies self._runonce(runstrats) File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\cerebro.py", line 1695, in _runonce strat._oncepost(dt0) File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\strategy.py", line 313, in _oncepost self.prenext() File "C:/Users/marketwizard/PycharmProjects/MW_Backtests/01_WSTF_EMA_Crossover_50_200_Flip_LongShort/main.py", line 133, in prenext print('Prenext: Cash: {}: , Order Ref: {}, Order Size: {}'.format(cash, order.ref, order.size)) AttributeError: 'NoneType' object has no attribute 'ref'
I also didn't understand what do you mean with "signal value" ?
-
@marketwizard said in Flipping a position from long to short:
The error:
in the
next
there is no order object, at least based on your script above.ref
andsize
can be accessed in thenotify_order
. This description in the docs can help you -
https://backtrader.com/docu/order/#reference-order-and-associated-classes@marketwizard said in Flipping a position from long to short:
I also didn't understand what do you mean with "signal value" ?
Values of the indicators which you use as signals to issue buy/sell orders.
Just to reiterate - logs should give a clear picture of the backtest flow. This is the only way to check that backtest is going as expected.
-
@ab_trader I understand why its important to print these informations, it will also help me for further project.
So if I understand that well, following informations should be printed:
- In prenext() / next() I printed: Cash, Brokervalue, Signal Values (both ema + crossover)
- In notify order: date, status, order ref, size
- In notify trade: date, Closed price, Pnl Gross / Net
Here are the results (I deleted most of the outputs between the orders because it was to long to be posted here):
AAPL_DAILY_ALPHA_VANTAGE.txt next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.28, Slow EMA: nan, CrossOver: nan Prenext(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.28, Slow EMA: 0.31, CrossOver: nan next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.28, Slow EMA: 0.31, CrossOver: nan next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.31, Slow EMA: 0.32, CrossOver: 0.0 next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.31, Slow EMA: 0.32, CrossOver: 0.0 next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.32, Slow EMA: 0.32, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2002-01-03, Status 2: Ref: 1, Size: 27864.49008946133, Price: NA next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.32, Slow EMA: 0.32, CrossOver: 0.0 next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.35, Slow EMA: 0.35, CrossOver: 0.0 next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.35, Slow EMA: 0.35, CrossOver: 0.0 next(): Cash: 10000.0, Broker Value: 10000.0, Fast EMA: 0.34, Slow EMA: 0.35, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2002-06-24, Status 2: Ref: 2, Size: -38530.7192334889, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2002-06-24, Status 4: Ref: 2, Size: -38530.7192334889, Price: NA Created: 2002-06-21 23:59:59.999989 Price: 0.259533177655 Size: -38530.7192334889 -------------------------------------------------------------------------------- next(): Cash: 19902.72, Broker Value: 9344.86, Fast EMA: 0.24, Slow EMA: 0.24, CrossOver: 0.0 next(): Cash: 19902.72, Broker Value: 9309.25, Fast EMA: 0.24, Slow EMA: 0.24, CrossOver: 0.0 next(): Cash: 19902.72, Broker Value: 9077.8, Fast EMA: 0.24, Slow EMA: 0.24, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2003-05-23, Status 2: Ref: 3, Size: 38530.7192334889, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2003-05-23, Status 4: Ref: 3, Size: 38530.7192334889, Price: NA Created: 2003-05-22 23:59:59.999989 Price: 0.280942739491 Size: 38530.7192334889 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2003-05-23 23:59:59.999989, Close Price: 0.2583, Profit, Gross -855.38, Net -959.18 -------------------------------------------------------------------------------- next(): Cash: 9040.82, Broker Value: 9040.82, Fast EMA: 1.9, Slow EMA: 1.89, CrossOver: 0.0 next(): Cash: 9040.82, Broker Value: 9040.82, Fast EMA: 1.89, Slow EMA: 1.89, CrossOver: 0.0 next(): Cash: 9040.82, Broker Value: 9040.82, Fast EMA: 1.88, Slow EMA: 1.89, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2006-07-07, Status 2: Ref: 4, Size: -5262.402041686774, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2006-07-07, Status 4: Ref: 4, Size: -5262.402041686774, Price: NA Created: 2006-07-06 23:59:59.999989 Price: 1.71800181814 Size: -5262.402041686774 -------------------------------------------------------------------------------- next(): Cash: 17989.82, Broker Value: 9008.98, Fast EMA: 1.88, Slow EMA: 1.88, CrossOver: 0.0 next(): Cash: 17989.82, Broker Value: 6940.47, Fast EMA: 1.87, Slow EMA: 1.88, CrossOver: 0.0 next(): Cash: 17989.82, Broker Value: 6708.66, Fast EMA: 1.88, Slow EMA: 1.88, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2006-08-04, Status 2: Ref: 5, Size: 5262.402041686774, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2006-08-04, Status 4: Ref: 5, Size: 5262.402041686774, Price: NA Created: 2006-08-03 23:59:59.999989 Price: 2.14372864487 Size: 5262.402041686774 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2006-08-04 23:59:59.999989, Close Price: 1.7090999999999998, Profit, Gross -1875.52, Net -1974.84 -------------------------------------------------------------------------------- next(): Cash: 7065.98, Broker Value: 7065.98, Fast EMA: 1.89, Slow EMA: 1.88, CrossOver: 0.0 next(): Cash: 7065.98, Broker Value: 7065.98, Fast EMA: 4.46, Slow EMA: 4.44, CrossOver: 0.0 next(): Cash: 7065.98, Broker Value: 7065.98, Fast EMA: 4.44, Slow EMA: 4.43, CrossOver: 0.0 next(): Cash: 7065.98, Broker Value: 7065.98, Fast EMA: 4.42, Slow EMA: 4.43, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-03-03, Status 2: Ref: 6, Size: -1834.7202969781647, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-03-03, Status 4: Ref: 6, Size: -1834.7202969781647, Price: NA Created: 2008-02-29 23:59:59.999989 Price: 3.85125672052 Size: -1834.7202969781647 -------------------------------------------------------------------------------- next(): Cash: 14064.03, Broker Value: 7184.0, Fast EMA: 4.39, Slow EMA: 4.42, CrossOver: 0.0 next(): Cash: 14064.03, Broker Value: 5677.77, Fast EMA: 4.38, Slow EMA: 4.39, CrossOver: 0.0 next(): Cash: 14064.03, Broker Value: 5377.09, Fast EMA: 4.39, Slow EMA: 4.39, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-04-17, Status 2: Ref: 7, Size: 1834.7202969781647, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-04-17, Status 4: Ref: 7, Size: 1834.7202969781647, Price: NA Created: 2008-04-16 23:59:59.999989 Price: 4.73474770392 Size: 1834.7202969781647 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2008-04-17 23:59:59.999989, Close Price: 3.8334, Profit, Gross -1680.79, Net -1759.52 -------------------------------------------------------------------------------- next(): Cash: 5306.46, Broker Value: 5306.46, Fast EMA: 4.41, Slow EMA: 4.4, CrossOver: 0.0 next(): Cash: 5306.46, Broker Value: 5306.46, Fast EMA: 4.89, Slow EMA: 4.91, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2008-09-24, Status 2: Ref: 8, Size: -1358.079892234643, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2008-09-24, Status 4: Ref: 8, Size: -1358.079892234643, Price: NA Created: 2008-09-23 23:59:59.999989 Price: 3.90732204792 Size: -1358.079892234643 -------------------------------------------------------------------------------- next(): Cash: 10604.32, Broker Value: 5219.63, Fast EMA: 4.85, Slow EMA: 4.9, CrossOver: 0.0 next(): Cash: 10604.32, Broker Value: 5183.65, Fast EMA: 3.55, Slow EMA: 3.54, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2009-05-12, Status 2: Ref: 9, Size: 1358.079892234643, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2009-05-12, Status 4: Ref: 9, Size: 1358.079892234643, Price: NA Created: 2009-05-11 23:59:59.999989 Price: 3.99142003902 Size: 1358.079892234643 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2009-05-12 23:59:59.999989, Close Price: 3.9206, Profit, Gross -95.74, Net -149.47 -------------------------------------------------------------------------------- next(): Cash: 5156.99, Broker Value: 5156.99, Fast EMA: 3.56, Slow EMA: 3.55, CrossOver: 0.0 next(): Cash: 5156.99, Broker Value: 5156.99, Fast EMA: 17.73, Slow EMA: 17.73, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2012-12-21, Status 2: Ref: 10, Size: -317.99431705713874, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2012-12-21, Status 4: Ref: 10, Size: -317.99431705713874, Price: NA Created: 2012-12-20 23:59:59.999989 Price: 16.2172309168 Size: -317.99431705713874 -------------------------------------------------------------------------------- next(): Cash: 10197.12, Broker Value: 5063.86, Fast EMA: 17.67, Slow EMA: 17.72, CrossOver: 0.0 next(): Cash: 10197.12, Broker Value: 5178.59, Fast EMA: 14.81, Slow EMA: 14.82, CrossOver: 0.0 next(): Cash: 10197.12, Broker Value: 5098.51, Fast EMA: 14.86, Slow EMA: 14.84, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2013-09-10, Status 2: Ref: 11, Size: 317.99431705713874, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2013-09-10, Status 4: Ref: 11, Size: 317.99431705713874, Price: NA Created: 2013-09-09 23:59:59.999989 Price: 16.0336449151 Size: 317.99431705713874 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2013-09-10 23:59:59.999989, Close Price: 15.929399999999998, Profit, Gross -33.45, Net -84.27 -------------------------------------------------------------------------------- next(): Cash: 5072.71, Broker Value: 5072.71, Fast EMA: 14.89, Slow EMA: 14.84, CrossOver: 0.0 next(): Cash: 5072.71, Broker Value: 5072.71, Fast EMA: 27.13, Slow EMA: 27.04, CrossOver: 0.0 next(): Cash: 5072.71, Broker Value: 5072.71, Fast EMA: 27.06, Slow EMA: 27.02, CrossOver: 0.0 next(): Cash: 5072.71, Broker Value: 5072.71, Fast EMA: 26.99, Slow EMA: 27.0, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-09-08, Status 2: Ref: 12, Size: -201.31946881211454, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-09-08, Status 4: Ref: 12, Size: -201.31946881211454, Price: NA Created: 2015-09-04 23:59:59.999989 Price: 25.1973266469 Size: -201.31946881211454 -------------------------------------------------------------------------------- next(): Cash: 10229.99, Broker Value: 5016.15, Fast EMA: 26.94, Slow EMA: 26.99, CrossOver: 0.0 next(): Cash: 10229.99, Broker Value: 4667.83, Fast EMA: 26.81, Slow EMA: 26.82, CrossOver: 0.0 next(): Cash: 10229.99, Broker Value: 4740.1, Fast EMA: 26.82, Slow EMA: 26.82, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-11-24, Status 2: Ref: 13, Size: 201.31946881211454, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-11-24, Status 4: Ref: 13, Size: 201.31946881211454, Price: NA Created: 2015-11-23 23:59:59.999989 Price: 27.2695554929 Size: 201.31946881211454 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2015-11-24 23:59:59.999989, Close Price: 25.7461, Profit, Gross -287.12, Net -340.39 -------------------------------------------------------------------------------- next(): Cash: 4732.32, Broker Value: 4732.32, Fast EMA: 26.85, Slow EMA: 26.83, CrossOver: 0.0 next(): Cash: 4732.32, Broker Value: 4732.32, Fast EMA: 26.8, Slow EMA: 26.83, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2015-12-17, Status 2: Ref: 14, Size: -183.52956094666692, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2015-12-17, Status 4: Ref: 14, Size: -183.52956094666692, Price: NA Created: 2015-12-16 23:59:59.999989 Price: 25.7850726843 Size: -183.52956094666692 -------------------------------------------------------------------------------- next(): Cash: 9469.75, Broker Value: 4837.74, Fast EMA: 26.74, Slow EMA: 26.81, CrossOver: 0.0 next(): Cash: 9469.75, Broker Value: 4764.73, Fast EMA: 24.23, Slow EMA: 24.18, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2016-08-24, Status 2: Ref: 15, Size: 183.52956094666692, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2016-08-24, Status 4: Ref: 15, Size: 183.52956094666692, Price: NA Created: 2016-08-23 23:59:59.999989 Price: 25.6363355636 Size: 183.52956094666692 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2016-08-24 23:59:59.999989, Close Price: 25.942599999999995, Profit, Gross 68.53, Net 21.26 -------------------------------------------------------------------------------- next(): Cash: 4753.58, Broker Value: 4753.58, Fast EMA: 24.27, Slow EMA: 24.2, CrossOver: 0.0 next(): Cash: 4753.58, Broker Value: 4753.58, Fast EMA: 47.07, Slow EMA: 47.0, CrossOver: 0.0 next(): Cash: 4753.58, Broker Value: 4753.58, Fast EMA: 46.81, Slow EMA: 46.93, CrossOver: -1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2018-12-17, Status 2: Ref: 16, Size: -117.64482729046028, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2018-12-17, Status 4: Ref: 16, Size: -117.64482729046028, Price: NA Created: 2018-12-14 23:59:59.999989 Price: 40.4062246176 Size: -117.64482729046028 -------------------------------------------------------------------------------- next(): Cash: 9482.54, Broker Value: 4773.2, Fast EMA: 46.54, Slow EMA: 46.87, CrossOver: 0.0 next(): Cash: 9482.54, Broker Value: 3709.84, Fast EMA: 44.54, Slow EMA: 44.49, CrossOver: 1.0 -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Accepted 2019-04-09, Status 2: Ref: 17, Size: 117.64482729046028, Price: NA -------------------------------- NOTIFY ORDER -------------------------------- AutoOrderedDict() Order Completed 2019-04-09, Status 4: Ref: 17, Size: 117.64482729046028, Price: NA Created: 2019-04-08 23:59:59.999989 Price: 49.0688976331 Size: 117.64482729046028 -------------------------------------------------------------------------------- -------------------------------- NOTIFY TRADE -------------------------------- 2019-04-09 23:59:59.999989, Close Price: 40.3989, Profit, Gross -1026.32, Net -1078.98 -------------------------------------------------------------------------------- next(): Cash: 3674.6, Broker Value: 3674.6, Fast EMA: 44.71, Slow EMA: 44.54, CrossOver: 0.0 next(): Cash: 3674.6, Broker Value: 3674.6, Fast EMA: 128.65, Slow EMA: 109.13, CrossOver: 0.0 next(): Cash: 3674.6, Broker Value: 3674.6, Fast EMA: 128.78, Slow EMA: 109.36, CrossOver: 0.0 Process finished with exit code 0
And my script:
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 = 10000 data_path = XXX benchmark_path = XXX list_path = XXX project_path = XXX 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) ) # Initialize the elements which are needed for the strategy (indicators, etc...) def __init__(self): # Define the indicators self.ema_fast = bt.indicators.EMA(self.data.close, period=50, plot=True, subplot=False) self.ema_slow = bt.indicators.EMA(self.data.close, period=200, 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 start(self): self.order = None # sentinel to avoid operations on pending order 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() if self.order: return # pending order execution if self.cross > 0.0: ''' if self.position: # Calculation of the Stock Qty to buy depending on our risk strategy self.close(tradeid=self.curtradeid) ''' portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) self.curtradeid = next(self.tradeid) self.buy() if self.cross < 0.0: ''' if self.position: self.close(tradeid=self.curtradeid) ''' portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / self.data.close[0]) self.curtradeid = next(self.tradeid) self.sell() 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__': NA = '-' # open file in read mode with open(list_path, 'r') as read_obj: tickers = reader(read_obj) for ticker in tickers: tick = str(ticker[0]) cerebro = bt.Cerebro() endDate = date(2021, 1, 17) fromDate = (endDate - timedelta(days=period)) startDate = fromDate.strftime('%Y-%m-%d') # filename = '%s_%s_%s.txt' % (ticker, startDate, endDate) filename = '%s_DAILY_ALPHA_VANTAGE.txt' % tick datapath = os.path.join(data_path, filename) print(os.path.abspath(datapath)) # ''' if not os.path.isfile(datapath): print('file: %s not found' % filename) sys.exit() # ''' data = bt.feeds.GenericCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime(fromDate.year, fromDate.month, fromDate.day), # Do not pass values before this date todate=datetime(datetime.today().year, datetime.today().month, datetime.today().day), nullvalue=0.0, dtformat=('%Y-%m-%d'), datetime=0, open=1, high=2, low=3, close=4, volume=5, openinterest=-1 ) cerebro.adddata(data) # 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]
-
@marketwizard good. since no question asked, i'll try to address the topic name
flipping positions
. right now your script open position on one signal and than close it with the opposite signal. if you want to flip position, than the position should be opened with the signal, closed with the opposite signal and than new position should be opened.interesting observation - very first order (ref 1) was only accepted, but never rejected and completed.
if you need to flip position and no other fancy stuff, i would recommend you to use target orders. in this case
bt
will close position and open new one automatically. -
@ab_trader I looked at the documentation concerning the target order and I tried the following piece of code in next():
if self.order: return # pending order execution if self.cross > 0.0: self.order = self.order_target_percent(target=self.p.percent) if self.cross < 0.0: self.order = self.order_target_percent(target=self.p.percent)
(self.p.percent is set to 100)
However, it seems that no tra
-
*However it seems that no trade is executed...
-
@marketwizard said in Flipping a position from long to short:
if self.order:
return # pending order executionif self.cross > 0.0: self.order = self.order_target_percent(target=self.p.percent) if self.cross < 0.0: self.order = self.order_target_percent(target=self.p.percent)
I think you need criteria for position as well. eg:
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)
And make the short target negative.