Setting Priority for AtStop/AtLimit Orders

Modified on 2020/08/11 09:01 by Eugene — Categorized as: Community Components

When backtesting a Strategy on daily data which uses AtStop/AtLimit orders in Portfolio Simulation mode, some trades can be dropped due to insufficent funds. Setting Position.Priority would help to instruct Wealth-Lab which trades to take and which to discard. For realistic results, higher priority should be assigned to those trades that would have been filled earlier, looking at intraday data.

Quote the QuickRef:
Generally speaking, you should not assign Priority for Strategies that use AtLimit/AtStop entries. Doing so may create a peeking effect since it's often not possible to know which limit (or stop) orders will execute first when orders are placed for multiple instruments. You can, however, realistically use the inverse of the HHmm time-of-day as the correct Priority value. In other words, trades that occur earlier in the day should be assigned higher priority.

These methods help you solve this problem, one by providing a quick approximation, and another being precise, but requires intraday data.

LimitPriorityLong

Syntax

public static double LimitPriorityLong(this WealthScript ws, double p, int bar)

public double LimitPriorityLong(double p, int bar)

Parameter Description

pLimit price
barSignal bar

This function, created by Andrew Vishnyakov (avishn), helps to estimate which limit orders will realistically be hit first - without dropping to the intraday data level. According to its author, it gives quick and dirty approximation and is useful when scanning large data sets.



IntradayFillPriorityEstimate

Syntax

public static double IntradayFillPriorityEstimate(this WealthScript ws, bool longPos, bool limit, double price, int eodBar)

public double IntradayFillPriorityEstimate(bool longPos, bool limit, double price, int eodBar)

Parameter Description

longPos true for long, false for short positions
limit true for limit, false for stop orders
price Signal price
eodBar Alert bar

This function, created by Andrew (avishn), helps estimate which limit orders will realistically be hit first - without dropping to the intraday data level. Like the original LimitPriorityLong, superseded by this function, it gives an approximation and is useful when scanning large data sets. It supports both long and short as well as limit and stop orders.

Example

Here is a code example to illustrate the IntradayFillPriorityEstimate method:

Example using C# extension methods:

...
if (BuyAtLimit(bar + 1,price) != null) {
	LastActivePosition.Priority = this.IntradayFillPriorityEstimate(true, true, price, bar + 1);

Legacy syntax example:


using Community.Components; // IntradayFillPriorityEstimate is here
/*** Requires installation of Community.Components Extension from www.wealth-lab.com > Extensions ***/

... // Create an instance of the PositionHelper class PositionHelper ph = new PositionHelper( this );

... for(int bar = 20; bar < Bars.Count-1; bar++) { ... if (BuyAtLimit(bar + 1,price) != null) { LastActivePosition.Priority = ph.IntradayFillPriorityEstimate(true, true, price, bar + 1); ... }



SetTimeOfDayPriority

Syntax

public static void SetTimeOfDayPriority(this WealthScript ws, IList<Position> positions, string intradayDataSet)     // baseline method syntax
public static void SetTimeOfDayPriority(this WealthScript ws, int barInterval)
public static void SetTimeOfDayPriority(this WealthScript ws, int barInterval, DataSource dataSource)

public void SetTimeOfDayPriority(IList<Position> positions, string intradayDataSet) public void SetTimeOfDayPriority(int barInterval) // This call is valid only for the Fidelity DataStore

Parameter Description

positionsPass the list of Positions that have been established to date by the Strategy.
intradayDataSetThe exact name of any intraday DataSet that corresponds to the WealthLab.DataStore provider to be used to set priorities. For example, if you were running the script on a Russell 1000 DataSet, you could specify a 1-minute intraday DataSet for the Dow 30 provided that it was a WealthLab.DataStore of 1-minute data that also contained data for the Russell 1000 symbols.
barIntervalThe intraday interval of the DataSource you want to use to set priority by time of day. This "barInterval" method call assumes the FidelityStaticProvider.

Description

This method, created by Robert Sucher (Cone), avoids the task of rewriting the original Strategy to work on intraday data, and accesses corresponding intraday data from the same Strategy running on daily data. (For more details, see this KB article: Intraday / Multi-Time Frame | Accessing Intraday data from Daily.
Usage Notes:
  1. Valid for scripts that trade 1-symbol only
  2. Before running the trading script, update your intraday DataSet(s), or, disable File > Update Data on Demand.
  3. Can be used with any WealthLab.DataStore intraday data (Fidelity, IQFeed, etc.)
  4. In general, following the backtest, check the debug window for status messages occurring during the priority-setting process.
  5. When a probable data spike is detected, the output is shown in Wealth-Lab's debug window. This output will also contain the OHLC/V data based on the intraday data, which you can use to manually correct the Daily bar. After making corrections, re-run the backtest. Note that Position.Priority is set to -10000 for suspected spikes. Instead of correcting the data, you could use the Position Options sizer to "Reject a Position with Priority... Less than -1700" to filter these unrealistic trades.

User-controlled priority (v2020.01 and up) Since an identical priority is assigned to multiple Positions that are filled in the same intraday interval used for TOD priority, Wealth-Lab creates a fixed, pseudo-random priority. You can now control this "intra-bar" selection by assigning your own priority whose absolute value should be less than 1e7 as follows:
  1. If you assign 0 to Position.Priority, SetTimeOfDayPriority will work as it always did (Wealth-Lab pseudo-random priority).
  2. If you don't assign anything to Position.Priority, the results will be random for "ties" because Wealth-Lab automatically assigns a random number to priority.
  3. If you assign Position.Priority, trades will favor the highest priority you assign within the intraday interval used to check time-of-day. Example, assume your backtest has enough cash for 4 trades trades and you use 5-minute bars for TOD priority. 3 trades occur in the 0935 interval, 3 more occur in the 0940 interval, and 5 more occur later in the day. Using SetTimeOfDayPriority will choose the 3 trades at 0935 but only 1 trade with the highest priority at 0940, and none thereafter.

User-controlled priority may be used to customers trading EOD strategies but who delay placing orders (at the risk of slippage or non-fills) to pick trades in cash-limited scenarios by their own defined priority.

Example

Here is a code example to illustrate the SetTimeOfDayPriority method:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace WealthLab.Strategies { public class MyStrategy : WealthScript { protected override void Execute() { ClearDebug(); for(int bar = 20; bar < Bars.Count; bar++) { if (IsLastPositionActive) { Position p = LastPosition; if (bar - p.EntryBar > 2) SellAtMarket(bar + 1, p); } else { double limitPrice = 0.96 * Close[bar]; Position p = BuyAtLimit(bar + 1, limitPrice); } } /* Call the method after the trading loop */

// For Fidelity WLP users with Fidelity intraday data (only) //this.SetTimeOfDayPriority(5);

// Universal approach for any intraday data provider this.SetTimeOfDayPriority(Positions, "[i] ActiveTrader Standard Stock Portfolio (M5)"); /* Check priority - OPTIONAL! */ //int j = 0; //foreach (Position p in Positions) //{ // j++; // PrintDebug(Bars.Symbol + "\t" + j + "\t" + p.Priority + "\t" + p.EntryDate.ToShortDateString()); //} } } }