- ago
I was trying to implement the following TradeStation EasyLanguage code in WL7:
QUOTE:
If Trigger Crosses Over MA then Buy Next Bar at Close - 0.35*(High-Low) Limit;
If Trigger Crosses Under MA then Sell Short Next Bar at Close + 0.35*(High - Low) Limit;


I'm not that familiar with TradeStation. It confused me that they were only opening new positions without closing the existing ones. It occurred to me this was a SAR (Sell And Reverse) strategy and TradeStation must be implicitly closing existing positions when it reverses the trade (Buy long to Short; or Short to Buy long).

Does WL7 have a feature to implicitly close a trade in the opposite direction with this type of strategy?? It would simplify code for a SAR system.
0
1,351
Solved
9 Replies

Reply

Bookmark

Sort
- ago
#1
Creating a SAR type of system is not very complex in WL7 code:

https://www.wealth-lab.com/Discussion/Reverse-into-short-position-at-market-close-6914
https://www.wealth-lab.com/Discussion/Stop-and-Reverse-not-working-as-expected-6950
0
- ago
#2
I guess the answer is no you don't have a feature to automatically close existing positions when reversing the trade.

I get how to code a SAR in WL, but those examples show how a simple strategy can result in a lot of code. A more complex strategy with protective stops that are expected to reverse could get confusing.

It just seemed like a nice feature to have for those wishing to write SAR strategies. If I converted the EasyLanguage code to WL without adding the appropriate closing trades, there'd be a lot of dangling positions causing NSFs.
1
- ago
#3
If Dion agrees to it you could create a feature request for this?
0
- ago
#4
No need. I realized after backtesting it may appear "easy" to only code the entry trades and have the exit trades done automatically, it didn't always produce the desired results. It was better for the strategy author to have control of the exit trades too.

Let's just take one line of the earlier example...
QUOTE:
If Trigger Crosses Over MA then Buy Next Bar at Close - 0.35*(High-Low) Limit;


After crossing over a MA this strategy is looking for a pullback to get in. But what if it is so bullish that it gaps up -- it will not buy due to the limit price. With a SAR I will most likely have an open short position. If covering the short is contingent on the buy execution, you could be left in a short position that you needed to exit. This happened numerous times when I wrote the cover trade similar to the buy. It was better to cover at market to ensure I exited the short position and then let the buy trade go unexecuted. Probably not a true SAR, but safer than the original code implied.

So I realized the way WL7 works now is fine with me. This was just an exercise in a book I was trying to see how it backtested. I got my answer.
0
Cone8
 ( 6.71% )
- ago
#5
It's not really clear how the Easy Language code should work. The way it reads is that it executes at a "Limit" price on the bar after a crossover. First of all, that's not "Stop" and reverse. Second, what happens if the "Limit" price isn't hit on the bar after the crossover? You'd have to wait for another crossover condition to happen before a trade could occur. I think it should be called "Confusing" instead of Easy Language.

Here's a mockup for WL7. You can copy the SAR() method and use it as shown. The Price parameter is optional and will use Market orders if omitted. Seems to work fine.

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) {          _ma1 = SMA.Series(bars.Close, 20);          _ma2 = SMA.Series(bars.Close, 50);          PlotIndicator(_ma1, Color.Blue);          PlotIndicator(_ma2, Color.Black);       } public override void Execute(BarHistory bars, int idx) {          double trigger = bars.Close[idx] - 0.35 * (bars.High[idx] - bars.Low[idx]);          bool enterlong = _ma1.CrossesOver(_ma2, idx);          bool exitlong = _ma1.CrossesUnder(_ma2, idx);           // Alternatively          //         bool enterlong = _ma1[idx] > _ma2[idx]; //         bool exitlong = _ma1[idx] < _ma2[idx];          SAR(bars, enterlong, exitlong, OrderType.Stop, trigger); }       //copy and paste this "as is"       public void SAR(BarHistory bars, bool entryLong, bool exitLong, OrderType orderType, double price = 0)       {          //start a position          if (OpenPositions.Count == 0)          {             if (entryLong)             {                if (price == 0)                                  PlaceTrade(bars, TransactionType.Buy, OrderType.Market);                               else                   PlaceTrade(bars, TransactionType.Buy, orderType, price);             }             else if (exitLong)             {                if (price == 0)                   PlaceTrade(bars, TransactionType.Short, OrderType.Market);                else                   PlaceTrade(bars, TransactionType.Short, orderType, price);             }          }          else if (HasOpenPosition(bars, PositionType.Long))          {             if (exitLong)             {                if (price == 0)                {                   PlaceTrade(bars, TransactionType.Sell, OrderType.Market);                   PlaceTrade(bars, TransactionType.Short, OrderType.Market);                }                else                {                   PlaceTrade(bars, TransactionType.Sell, orderType, price);                   PlaceTrade(bars, TransactionType.Short, orderType, price);                }             }          }          else          {             if (entryLong)             {                if (price == 0)                {                   PlaceTrade(bars, TransactionType.Cover, OrderType.Market);                   PlaceTrade(bars, TransactionType.Buy, OrderType.Market);                }                else                {                   PlaceTrade(bars, TransactionType.Cover, orderType, price);                   PlaceTrade(bars, TransactionType.Buy, orderType, price);                }             }          }       }       SMA _ma1;       SMA _ma2; } }


0
Best Answer
Cone8
 ( 6.71% )
- ago
#6
Edit -
I changed the code above to let you enter the OrderType you want to use, Stop or Limit, when a price parameter is passed.
0
- ago
#7
QUOTE:
It's not really clear how the Easy Language code should work.


I agree. The book I was reading had only the script for entering positions, so I assumed the script would automatically generate exit trades when the enter trades were executed. SAR may not have been the correct term to use as it wasn't a stop and reverse.

I did not provide the complete strategy in Post #1. There were protective stops in the script as well which made it more complicated. I was getting stopped out on a short position causing a buy long trade and then cross over the MA causing another buy long. That caused an NSF position (sizing was 80% of equity) until I added code to check if I already had a long position open when I had a cross over. Designing how I wanted the script to work in WL7 seemed too complicated. I found myself with more questions than answers. It was better to leave the strategy author with providing the details.
0
- ago
#8
This is how I pictured a method to specify only the enter trades for SAR strategies...

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript { public class SAR_Crossover : UserStrategyBase {       public Parameter _spUseStops;       public SAR_Crossover()       {          _spUseStops = AddParameter("Use Stops", ParameterTypes.Int32, 0, 0, 1, 1);       }        //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          _MaShort = EMA.Series(bars.Close, 12);          _MaLong = EMA.Series(bars.Close, 26);          PlotTimeSeriesLine(_MaShort, _MaShort.Description, "Price", Color.Orange, 1, LineStyles.Solid);          PlotTimeSeriesLine(_MaLong, _MaLong.Description, "Price", Color.Red, 1, LineStyles.Solid);       } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) {          bool UseStops = (_spUseStops.AsInt != 0 ? true : false);           if (_MaShort.CrossesOver(_MaLong, idx) ) {             if (UseStops)             {                double StopPrice = bars.Close[idx] + 0.35 * (bars.High[idx] - bars.Low[idx]);                PlaceSARTrade(bars, TransactionType.Buy, OrderType.Stop, StopPrice, "Go Long w/ Stop");             }             else             {                PlaceSARTrade(bars, TransactionType.Buy, OrderType.Market, 0.0, "Go Long");             }          } else if (_MaShort.CrossesUnder(_MaLong, idx)) {             if (UseStops)             {                double StopPrice = bars.Close[idx] - 0.35 * (bars.High[idx] - bars.Low[idx]);                PlaceSARTrade(bars, TransactionType.Short, OrderType.Stop, StopPrice, "Go Short w/ Stop");             }             else             {                PlaceSARTrade(bars, TransactionType.Short, OrderType.Market, 0.0, "Go Short");             }          } }       public Transaction PlaceSARTrade(BarHistory bars, TransactionType transType, OrderType orderType, Double price, String signalName)       {          Transaction openTransaction = null;          // Only do a reverse trade when entering positions          if ( transType == TransactionType.Buy || transType == TransactionType.Short)          {             // Exit transaction should be opposite position             TransactionType exitTransType = (transType == TransactionType.Buy ? TransactionType.Cover : TransactionType.Sell);             if (HasOpenPosition(bars, (exitTransType == TransactionType.Sell ? PositionType.Long : PositionType.Short)))             {                PlaceTrade(bars, exitTransType, orderType, price, signalName);             }          }          openTransaction = PlaceTrade(bars, transType, orderType, price, signalName);          return openTransaction;       }       TimeSeries _MaShort;       TimeSeries _MaLong;    } }


I ran backtest using single symbol SPY. If you run this as a Market order, it seems to run fine ("Use Stops" parameter as zero). Once you run this using stop or limit orders, then you end up with dangling positions that should have been closed and a lot of NSF positions. That's when I realized it's not as simple to just specify the enter positions and expect the exit positions to close properly.
0
- ago
#9
Adding a boolean ExitAsMarketOrder helped fix the problem...

CODE:
      public Transaction PlaceSARTrade(BarHistory bars, TransactionType transType, OrderType orderType, double price = 0.0, string signalName = "", bool ExitAsMarketOrder = false)       {          Transaction OpenTransaction = null;          // Only do a reverse trade when entering positions          if ( transType == TransactionType.Buy || transType == TransactionType.Short)          {             // Exit transaction should be opposite position             TransactionType ExitTransType = (transType == TransactionType.Buy ? TransactionType.Cover : TransactionType.Sell);             if (HasOpenPosition(bars, (ExitTransType == TransactionType.Sell ? PositionType.Long : PositionType.Short)))             {                OrderType ExitOrderType = orderType;                double ExitPrice = price;                if (ExitAsMarketOrder)                {                   ExitOrderType = OrderType.Market;                   ExitPrice = 0.0;                }                PlaceTrade(bars, ExitTransType, ExitOrderType, ExitPrice, signalName);             }          }          OpenTransaction = PlaceTrade(bars, transType, orderType, price, signalName);          return OpenTransaction;       }


Now just set the boolean to true when placing stop or limit orders and it should close the position.

There may still be issues with the times when two moving averages touch and pull away. I think that can trigger a trade that could double your position.
0

Reply

Bookmark

Sort