Please tell me how to replace the code in WL6:
k = 1;
if (SellAtLimit(bar+1, LastPosition, LastPosition.EntryPrice + zATR[LastPosition.EntryBar-1], "limit"))
k = 0;
with the code in WL7:
if (PlaceTrade(...................)
k = 0
I always get the error.
k = 1;
if (SellAtLimit(bar+1, LastPosition, LastPosition.EntryPrice + zATR[LastPosition.EntryBar-1], "limit"))
k = 0;
with the code in WL7:
if (PlaceTrade(...................)
k = 0
I always get the error.
Rename
PlaceTrade returns a Transaction object while your code is treating it like a bool.
k = 1;
PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, LastPosition.EntryPrice + zATR[LastPosition.EntryBar -1], "limit");
if (bars.High[idx] > LastPosition.EntryPrice + zATR[LastPosition.EntryBar -1])
k = 0;
Logically, if the limit is triggered, "k" should become = 0. But it is always equal 1. :(
PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, LastPosition.EntryPrice + zATR[LastPosition.EntryBar -1], "limit");
if (bars.High[idx] > LastPosition.EntryPrice + zATR[LastPosition.EntryBar -1])
k = 0;
Logically, if the limit is triggered, "k" should become = 0. But it is always equal 1. :(
The problem is, LastPosition is not created yet at this stage. All WL7 has is the Transaction object at this point. After all of the processing for the symbols for this day, the backtesting engine then goes through and determines if any of the Transactions were filled. Only then are Position instances created.
Think of it like real trading. At the end of the trading day, you place your orders. These are the "Transactions". Then, the next day, some, none, or all of them get filled, resulting in the "Positions".
So, in WL7 code, you only can access the Positions that were already previously created.
So, in WL7 code, you only can access the Positions that were already previously created.
Since I am far from a programmer, it is probably better to demonstrate with an example.
The simplest example. How to make it so that when a limit order is triggered (closing a position), "k" becomes equal to zero, but so that "k" remains equal to one when a stop is triggered (closing a position)
The simplest example. How to make it so that when a limit order is triggered (closing a position), "k" becomes equal to zero, but so that "k" remains equal to one when a stop is triggered (closing a position)
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) { HH = new Highest(bars.High, 20); zSMA = new SMA(bars.Close, 20); k = 0; } public override void Execute(BarHistory bars, int idx) { if (bars.Low[idx] < zSMA[idx]) k = 1; if (!HasOpenPosition(bars, PositionType.Long)) { if (k == 1) PlaceTrade(bars, TransactionType.Buy, OrderType.Stop, HH[idx], "buy"); } else { PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, Math.Max(zSMA[idx], LastPosition.EntryPrice * 0.95), "stop"); //when a stop order is triggered, k = 1; PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, LastPosition.EntryPrice * 1.20, "limit"); // when a limit order is triggered, k = 0; } } //declare private variables below private IndicatorBase HH; private IndicatorBase zSMA; private int k; } }
This kind of deterministic logic based on the WL6 BuyAtLimit is actually a WL6 flaw, and not supported in WL7. You can't always know whether a limit or stop order triggers until the following bar.
You can issue two PlaceTrades however, and to get the most pessimistic result you can issue the Stop exit prior to the Limit exit.
You can issue two PlaceTrades however, and to get the most pessimistic result you can issue the Stop exit prior to the Limit exit.
If you can describe what you want the strategy to do in plain English I can mock it up and post the code.
1. Buy by stop order -- Highest(high, 20)
2. Set a stop loss -- stop 5% and trailing-stop SMA(20)
3. Set take-profit -- 20%
4. When take-profit is triggered, do not open new positions (do not place a buy order) until: Low[bar] < SMA[bar]
5. When the stop order is triggered, we place a new buy order.
(Attention, this is important: stop loss is sometimes triggered above SMA(20) -- stop 5%.
2. Set a stop loss -- stop 5% and trailing-stop SMA(20)
3. Set take-profit -- 20%
4. When take-profit is triggered, do not open new positions (do not place a buy order) until: Low[bar] < SMA[bar]
5. When the stop order is triggered, we place a new buy order.
(Attention, this is important: stop loss is sometimes triggered above SMA(20) -- stop 5%.
Here's how I would implement it - I'm using the SignalName property to see which signal the last closed position exited at.
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 { //Initialize public override void Initialize(BarHistory bars) { hh20 = Highest.Series(bars.High, 20); PlotIndicator(hh20); sma20 = SMA.Series(bars.Close, 20); PlotIndicator(sma20); } //Execute public override void Execute(BarHistory bars, int idx) { if (OpenPositions.Count == 0) { //determine if the last closed position exited with a profit target List<Position> positions = GetPositions(); if (positions.Count > 0) { Position pos = positions[positions.Count - 1]; if (pos.Tag == null) //we use this Tag to determine if we already considered this position if (pos.ExitSignalName == "Profit") { profitWasTriggered = true; pos.Tag = true; } } //clear this flag once low goes below SMA20 if (profitWasTriggered) if (bars.Low[idx] < sma20[idx]) profitWasTriggered = false; //place a buy if the flag was cleared if (!profitWasTriggered) PlaceTrade(bars, TransactionType.Buy, OrderType.Stop, hh20[idx]); //show a red zone on the chart while we are in a "no buy" zone if (profitWasTriggered) SetBackgroundColor(bars, idx, Color.FromArgb(64, 255, 0, 0)); } else { //stop loss exit double entryPrice = LastPosition.EntryPrice; double loss = entryPrice * 0.95; PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, loss, "StopLoss"); //trailing stop PlaceTrade(bars, TransactionType.Sell, OrderType.Stop, sma20[idx], "Trailing"); //profit target exit double profit = entryPrice * 1.2; PlaceTrade(bars, TransactionType.Sell, OrderType.Limit, profit, "Profit"); } } //private members private Highest hh20; private SMA sma20; private bool profitWasTriggered = false; } }
Many thanks. Everything works. Not an easy code for me, but I'll try to figure it out and understand. Thanks again.
"Here's how I would implement it..."
Where would "pos.Priority" figure into this flow assuming one wanted to assign a priority for competing trades with limited capital (portfolio mode) as in WL6?
Where would "pos.Priority" figure into this flow assuming one wanted to assign a priority for competing trades with limited capital (portfolio mode) as in WL6?
It would go right where you issue the buy ...
CODE:
Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.Stop, hh20[idx]); t.Weight = *some weight value*
Perfect. That wouldn't have worked in WL6, but it's right where it belongs. Thanks.
Assuming something similar to the community components logic in WL6 that allows for time based priority on an intraday scale (like 5 minute bars) will also be available? That is critical for backtest simulation (on a higher scale, based on limit entries) that gets as close to actual trading as possible.
Assuming something similar to the community components logic in WL6 that allows for time based priority on an intraday scale (like 5 minute bars) will also be available? That is critical for backtest simulation (on a higher scale, based on limit entries) that gets as close to actual trading as possible.
Yes we have something like that in the pipeline!
OK, thanks. FYI - my WL6 strategies rely on a combination of a user assigned priority on top of the intraday time based priority (to break any ties on the intraday scale as well).
Your Response
Post
Edit Post
Login is required