General
For backtesting purposes, to add the condition for exiting the position at the end of the day you do the following in a
single position strategy:
if( IsLastPositionActive )
{
// exit on the last bar of the day
if( Bars.IsLastBarOfDay(bar) )
ExitAtClose( bar, LastPosition, "Last Bar" );
}
Or in a
multiple open positions strategy that translates to:
for(int p = ActivePositions.Count - 1; p >= 0; p--)
{
Position pos = ActivePositionsp;
// exit on the last bar of the day
if( Bars.IsLastBarOfDay(bar) )
ExitAtClose( bar, pos, "Last Bar" );
}
However, sometimes it gets more tricky. Read on below:
Problem
I'm trying to code an intraday strategy that doesn't hold any positions overnight. In order to do this I need to keep the buy limit order from being placed on the bar before the last bar of the day, since if the order gets executed, I can't get out of it on the next bar. I'm using WL6 with autotrading so I can't use SellAtClose orders (not supported).
Code
The slider for "Today Close" allows a convenient switch to adjust for a short day's close at 1pm.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
namespace WealthLab.Strategies
{
public class MOCStrategy : WealthScript
{
/* Returns 24-hour time as an integer
* Example: 4pm = 1600 */
public int GetTime(int bar)
{
return Datebar.Hour * 100 + Datebar.Minute;
}
/* Adds minutes to an integer time (HHnn) and returns a HHnn time
* Example 1600 - 5 = 1555 */
public int AddIntegerTime( int t, int minutes )
{
int res = 60 * ( t / 100 ) + ( t % 100 ); // minutes past midnight
int res1 = res + minutes;
res1 = res1 / 60 * 100 + ( res1 % 60 );
if( res1 >= 2400 )
return (res1 % 2400 );
else if( res1 < 0 )
return AddIntegerTime( AddIntegerTime( 2400, minutes ), res );
else
return res1;
}
/* Returns the chart bar number of the first bar of the startDay.
* Example: Pass 2 to get the first bar of the second day */
public int FirstBarofDay( int startDay )
{
int cnt = 0;
for (int Bar = 0; Bar < Bars.Count; Bar++)
{
if( Bars.IntradayBarNumber( Bar ) == 0 ) cnt++;
if( cnt == startDay ) return Bar;
}
return Bars.Count;
}
/* Sliders
* minTradeBars are the min number of bars before the end of day that an entry is allowed
*/
private StrategyParameter todayCloseTime;
private StrategyParameter minTradeBars;
public MOCStrategy()
{
todayCloseTime = CreateParameter("Close Today", 1600, 1300, 1600, 300);
minTradeBars = CreateParameter("Min Trade Bars", 5, 2, 10, 1);
}
protected override void Execute()
{
int todayClose = todayCloseTime.ValueInt;
int minBarsInTrade = minTradeBars.ValueInt;
int lastChartBar = Bars.Count - 1;
int nextToLastBarTime = AddIntegerTime( todayClose, -Bars.BarInterval );
for(int bar = FirstBarofDay( 2 ); bar < Bars.Count - 1; bar++)
{
if( !IsLastPositionActive )
{
if ( bar < lastChartBar - minBarsInTrade )
{
BuyAtLimit(bar + 1, Bars.Lowbar * 0.995);
}
}
else
{
Position p = LastPosition;
if( (bar == lastChartBar) && (GetTime(bar) >= nextToLastBarTime) )
{
SetBarColor( bar, Color.Orange);
ExitAtMarket( bar + 1, p, "Exit at open of last bar");
}
else if ( (bar != lastChartBar) && Bars.IsLastBarOfDay(bar + 1) )
{
SetBarColor( bar, Color.Orange);
ExitAtMarket( bar + 1, p, "Exit at open of last bar");
}
else
{
// other exit logic here
}
}
}
}
}
}