Page History: Setting Priority for AtStop/AtLimit Orders
Compare Page Revisions
Page Revision: 2013/05/11 14:54
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
p | Limit price |
bar | Signal 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
positions | Pass the list of Positions that have been established to date by the Strategy. |
intradayDataSet | The 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. |
barInterval | The 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.
- Assumes 0 Slippage
- Automatically sets priority: Trades that occur earlier in the day are assigned higher priority
- Works for all AtStop/AtLimit order entry types
- Identifies probable Data Spikes in Daily data when the trade price occurs outside the range of the intraday data.
Usage Notes:
- Valid for scripts that trade 1-symbol only
- Before running the trading script, update your intraday DataSet(s), or, disable File > Update Data on Demand.
- Can be used with any WealthLab.DataStore intraday data (Fidelity, IQFeed, etc.)
- In general, following the backtest, check the debug window for status messages occurring during the priority-setting process.
- 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.
Example
Here is a code example to illustrate the
SetTimeOfDayPriority method:
Example using C# extension methods: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());
//}
}
}
}
Legacy syntax example:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using Community.Components; // SetTimeOfDayPriority here
/*** Requires installation of Community.Components Extension from www.wealth-lab.com > Extensions ***/
namespace WealthLab.Strategies
{
public class MyStrategy : WealthScript
{
protected override void Execute()
{
/* Create an instance of the PositionHelper class */
PositionHelper ph = new PositionHelper( this );
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)
//ph.SetTimeOfDayPriority(5);
// Universal approach for any intraday data provider
ph.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());
//}
}
}
}