- ago
For the below strategy in WL6.9, even with limit orders, SAR works perfectly.

CODE:
protected override void Execute()       {          DataSeries maFast = SMA.Series(Close, 50);          DataSeries maSlow = SMA.Series(Close, 200);          PlotSeries(PricePane, maFast, Color.Green, LineStyle.Solid, 2);          PlotSeries(PricePane, maSlow, Color.Red, LineStyle.Solid, 2);                    for(int bar = 360; bar < Bars.Count; bar++)          {             // Detect crossover/crossunder and store state in a variable             bool maXo = CrossOver(bar, maFast, maSlow);             bool maXu = CrossUnder(bar, maFast, maSlow);             // The first trade             if (Positions.Count == 0)             {                if (maXo)                   BuyAtLimit(bar + 1, Bars.Close[bar] * 1.003);                else if (maXu)                   ShortAtLimit(bar + 1, Bars.Close[bar] * 0.997);             }             else // Subsequent trades             {                Position p = LastPosition;                if (p.PositionType == PositionType.Long)                {                   if (maXu)                   {                      SellAtLimit(bar + 1, p, Bars.Close[bar] * 0.997);                      ShortAtLimit(bar + 1, Bars.Close[bar] * 0.997);                   }                }                else if (maXo)                {                   CoverAtLimit(bar + 1, p, Bars.Close[bar] * 1.003);                   BuyAtLimit(bar + 1, Bars.Close[bar] * 1.003);                }             }          }       }


I do have a check to ensure if limit orders fail then order will be filled in next bar to ensure SAR continues. All this works perfectly fine in WL6.9. The strategy works well in live trading.

In WL7, the same code is not able to implement SAR.

CODE:
//Initialize       public override void Initialize(BarHistory bars)       {          maFast = SMA.Series(bars.Close, 50);          maSlow = SMA.Series(bars.Close, 200);          PlotIndicator(maFast);          PlotIndicator(maSlow, Color.Red);       }       //Execute       public override void Execute(BarHistory bars, int idx)       {          StartIndex = 360;          // Detect crossover/crossunder and store state in a variable          maXo = maFast.CrossesOver(maSlow, idx);          maXu = maFast.CrossesUnder(maSlow, idx);             // The first trade             if (GetPositions().Count == 0)             {                if (maXo)                   PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Close[idx] * 1.003);                else if (maXu)                   PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.997);             }             else // Subsequent trades             {                Position p = LastPosition;                if (p.PositionType == PositionType.Long)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, bars.Close[idx] * 0.997);                      PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.997);                   }                }                else if (maXo)                {                   PlaceTrade(bars, TransactionType.Cover, OrderType.Limit, bars.Close[idx] * 1.003);                   PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Close[idx] * 1.003);                }             }          }       //private members       private bool maXo, maXu;       private SMA maFast;       private SMA maSlow;    }


These are the trades shown in WL6.9:


These are the trades shown in WL7:


Only long trades get entered and exit fine. But after exit, short trades don't get entered. Then the next long trade gets entered.

On changing the OrderType.Limit to OrderType.Market in WL7, a few short trades get entered but not all.


I have slippage disabled in preferences of both WL6.9 and WL7. I set the limit price to be 0.3% more (long) and less (short) than closing price to account for slippage in the code itself. This works well in live trading using WL6.9 but not in WL7. So I'm not sure why short trades are missing and why some but not all short trades get entered in at-market orders in WL7 with same code.

How do I get SAR strategy working in WL7?
0
994
Solved
22 Replies

Reply

Bookmark

Sort
- ago
#1
Hope this helps:
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy : UserStrategyBase {       public override void Initialize(BarHistory bars)       {          maFast = SMA.Series(bars.Close, 50);          maSlow = SMA.Series(bars.Close, 200);          PlotIndicator(maFast);          PlotIndicator(maSlow, Color.Red);          StartIndex = 200;       }       //Execute       public override void Execute(BarHistory bars, int idx)       {          // Detect crossover/crossunder and store state in a variable          maXo = maFast.CrossesOver(maSlow, idx);          maXu = maFast.CrossesUnder(maSlow, idx);          // The first trade          if (GetPositions().Count == 0)          {             if (maXo)                PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Close[idx] * 1.003);             else if (maXu)                PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.997);          }          else // Subsequent trades          {             Position p = LastPosition;             if (LastPosition != null)             {                if (FindOpenPosition(PositionType.Long) != null)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, bars.Close[idx] * 0.997);                      PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.997);                   }                }                else                   if (FindOpenPosition(PositionType.Short) != null)                {                   PlaceTrade(bars, TransactionType.Cover, OrderType.Limit, bars.Close[idx] * 1.003);                   PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Close[idx] * 1.003);                }             }          }       }       //private members       private bool maXo, maXu;       private SMA maFast;       private SMA maSlow; } }
0
- ago
#2
Hi Eugene,

The suggested code is not working either. The 1st buy and sell are correct but at the sell there is no short trade entered but at the next bar (10/12/2021 15:32) there is another buy trade instead.



I think the short position happens but in the next bar, it immediately sees short != null and covers the short and goes long without any conditions. I'm not sure why short is not shown here. There is another time 10/14/2021 13:53, where short position is entered and closed in the next bar.

I tried to include maXo check to cover any short positions and go long but there are no short positions shown. But all long positions are captured correctly this way.

CODE:
if (LastPosition != null)             {                if (FindOpenPosition(PositionType.Long) != null)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, bars.Close[idx] * 0.997, "sell");                      PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.997, "short");                   }                }                else                 if (FindOpenPosition(PositionType.Short) != null)                {                   if (maXo)                   {                      PlaceTrade(bars, TransactionType.Cover, OrderType.Limit, bars.Close[idx] * 1.003, "cover");                      PlaceTrade(bars, TransactionType.Buy, OrderType.Limit, bars.Close[idx] * 1.003, "buy");                   }                }             }




Please suggest what should be done to get short positions working.
0
- ago
#3
Hi,

Works for me on SPY daily data. What's your position size?
0
- ago
#4
Position size is $1000. Have you tried on 1-minute scale?
0
- ago
#5
SAR is designed with market orders in mind, I haven't looked at SAR with limit orders on 1-min scale.
0
- ago
#6
Please enable this feature as SAR works perfectly for limit orders and 1-minute scale in WL6.9.
0
- ago
#7
It works for me on 1-min scale either.
0
- ago
#8
I tried Market orderType on SPY 1-minute and SAR works. But with Limit orders it does not work. In WL6.9, SAR with limit orders works fine.

With both sell and short market order, I see correct long/short trades:


If I change the sell orderType to Limit then sell still happens but short trade fails even though I kept short as market order.

CODE:
if (FindOpenPosition(PositionType.Long) != null)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, bars.Close[idx] * 0.999, "sell");                      PlaceTrade(bars, TransactionType.Short, OrderType.Market, bars.Close[idx] * 0.999, "short");                   }                }




If I change sell order to market and short order to Limit then both long and short trade occurs correctly
CODE:
if (FindOpenPosition(PositionType.Long) != null)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Market, bars.Close[idx] * 0.999, "sell");                      PlaceTrade(bars, TransactionType.Short, OrderType.Limit, bars.Close[idx] * 0.999, "short");                   }                }


If I keep both sell and short order to Limit then short trade fails. Why is sell ordertype affecting short position from being placed? I also see cover trade orderType affects buy position. If cover trade orderType is not market then buy trade doesn't happen.

For other stocks like XBI, even with all PlaceTrade with market orderType, SAR doesn't work. Can you please resolve this issue so I can migrate to WL7.
0
- ago
#9
I haven't heard back. Is there a support ticket system I can file for WL7 for tracking this issue?
0
- ago
#10
This is the support system but I have nothing to add since the program is working correctly and there appears to be no "issue".

Just occurred to me that the entries behave as if they were market orders with slippage instead of market orders or real limit orders. Why does the code buy at limit above the close price and short at limit below the close price?
0
- ago
#11
The issue is that the code is not working in WL7 but works fine in WL6.9

Yes, it is kind of market order with slippage rather than pure limit order. The purpose is only to get into the trade to get SAR going rather than trying to use limit to maximize profit. If next minute bar opens higher than previous bar close when trying to go long then buy order may not get executed if the gap is big, which is why limit is set above close price when buying. Same for short at limit below close price, to ensure order is placed if next minute bar opens below last minute close. Using market order with slippage gives better prices than using pure market order.

Even with pure market order (no slippage) the stop-and-reverse code doesn't work correctly with other stocks like XBI. Please help determine why is it not working.

CODE:
public override void Initialize(BarHistory bars)       {          maFast = SMA.Series(bars.Close, 50);          maSlow = SMA.Series(bars.Close, 200);          PlotIndicator(maFast);          PlotIndicator(maSlow, Color.Red);          StartIndex = 200;       }       //Execute       public override void Execute(BarHistory bars, int idx)       {          // Detect crossover/crossunder and store state in a variable          maXo = maFast.CrossesOver(maSlow, idx);          maXu = maFast.CrossesUnder(maSlow, idx);          // The first trade          if (GetPositions().Count == 0)          {             if (maXo)                PlaceTrade(bars, TransactionType.Buy, OrderType.Market, bars.Close[idx], "first buy");             else if (maXu)                PlaceTrade(bars, TransactionType.Short, OrderType.Market, bars.Close[idx], "first short");          }          else // Subsequent trades          {             Position p = LastPosition;             if (LastPosition != null)             {                if (FindOpenPosition(PositionType.Long) != null)                {                   if (maXu)                   {                      PlaceTrade(bars, TransactionType.Sell, OrderType.Market, bars.Close[idx], "sell");                      PlaceTrade(bars, TransactionType.Short, OrderType.Market, bars.Close[idx], "short");                   }                }                else                 if (FindOpenPosition(PositionType.Short) != null)                {                   if (maXo)                   {                      PlaceTrade(bars, TransactionType.Cover, OrderType.Market, bars.Close[idx], "cover");                      PlaceTrade(bars, TransactionType.Buy, OrderType.Market, bars.Close[idx], "buy");                   }                }             }          }       }       //private members       private bool maXo, maXu;       private SMA maFast;       private SMA maSlow;




Here are the issues summarized:
1) Even with pure market orders (no slippage) all trades needed to get SAR going don't always get executed (issue seen in XBI).
2) Sell limit order prevents short market orders from being placed. If sell order is market then both sell/short orders get placed even if short order is a limit order.
3) Cover limit order prevents buy market orders from being placed. If cover order is market then both cover/buy orders get placed even if buy order is a limit order.
Issues 2) and 3) can be seen with both SPY and XBI

Is there no log or error message generated when a PlaceTrade command fails to execute a trade? This would help know why order was not executed. I tried to assign higher weights to trades that didn't executed but it didn't help.
0
Cone8
 ( 4.98% )
- ago
#12
I did a quick test with your code and didn't duplicate the problem.

1
- ago
#13
I noticed you had a position size of $10k. Whereas I had $1k. When I changed it to $10k, I only get 2 long trades and nothing else after that with the same code.



This is my strategy settings:


Not sure what's missing in my backtesting. I'm using build 27.
0
- ago
#14
How many NSF positions does the backtest have?

"What are NSF positions?'
https://www.wealth-lab.com/Support/Faq
0
Cone8
 ( 4.98% )
- ago
#16
I was using 10% of equity with 100K starting. But using precisely the settings you've shown, $10K fixed is the same. And, I can tell you're not using Slippage for Market orders, otherwise the prices would be adjusted slightly. Hmmm...

What's the answer to Eugene's NSF Positions?

0
Cone8
 ( 4.98% )
- ago
#17
Ah, okay, I didn't set my Starting Equity to only $10K. This is likely the problem. If you only start with $10K and use $10K sizes, after the losses of the first two trades, there's not enough capital in the Portfolio to open a new position, unless there happens to be a large gap.

Answer:
Wealth-Lab 7 doesn't have a "Raw Profit Mode" like Wealth-Lab 6.
0
Best Answer
- ago
#18
Here's the full pic of the trades with $10k fixed value



Here's the snapshot of Symbols tab:


I do have "Retain NSF positions" checked and I don't see any signals been generated for NSF positions as open. You can see there is no "Signals" tab in the pic.

With 10% equity of $100k, I see all trades showing up correctly for XBI. I also verified that limit orders are also working now with percent of equity setting. Is it because of NSF?

I just saw Cone's response - this makes sense. So shouldn't this be marked as NSF?
1
Cone8
 ( 4.98% )
- ago
#19
QUOTE:
Is it because of NSF?

Yes. Check the User Guide for the "Retain NSF" explanation. Unchecking it won't necessarily help entering positions, but it can alter the basic 1-Position strategy to remain in the Entry logic after a failed [NSF] trade.

Keep in mind that Slippage for Limit orders will prevent limit order execution unless the instrument trades beyond the limit price by the slippage amount.

0
- ago
#20
I meant to ask - why it didn't show me the unexecuted trades as NSF? It was hard to understand what was going on.
0
Cone8
 ( 4.98% )
- ago
#21
The Metric page tells you if there are NSF Positions. Depending on the backtest, there could be many hundreds or thousands of them. These are trades that aren't part of the backtest results, so they're not displayed.

If you really want to identify them, you can. Just add this to your script -

CODE:
public override void BacktestComplete() {          int k = 0;          foreach (Position p in Backtester.Positions)          {             if (p.NSF)             {                k++;                WriteToDebugLog(String.Format("{0}\t{1}\t{2}", p.Symbol, p.Quantity, p.EntryDateString));             }          }          WriteToDebugLog("NSF Count = " + k);    }
0
- ago
#22
QUOTE:
why it didn't show me the unexecuted trades as NSF?

NSF positions are not included in backtest results. When "Retain NSF Positions" is enabled (like you did), Wealth-Lab marks exit signals for NSFs on the Signals tab. They're there to let you exit a potential position in a live account that isn't included in the backtest results for having been rejected. So to see NSF positions, follow Cone's suggestion in Post #21.
0

Reply

Bookmark

Sort