This article illustrates various design patterns helpful when it comes to mixing of different time scale data in Wealth-Lab 6 - like intraday and daily.
Combining exits using yesterday's and today's prices
Here's code of a system that...
- Buys at 10:30 when today's open is higher than yesterday's close and price at 10:30 is higher than opening price
- Sells at close for the day
- Would like to place a stop at yesterday's close
Code
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()
{
double Stop = 0;
// Check for intraday data
if ( Bars.IsIntraday )
{
// Get daily bars
SetScaleDaily();
Bars daily = Bars;
RestoreScale();
daily = Synchronize( daily );
PlotSeries( PricePane, daily.Close, Color.Black, LineStyle.Dashed, 1 );
for(int bar = 20; bar < Bars.Count; bar++)
{
if( IsLastPositionActive )
{
if ( Bars.IsLastBarOfDay( bar ) )
SellAtClose( bar, LastPosition, "At Close" ); else
SellAtStop( bar+1, LastPosition, Stop, "Stop" );
} else
{
//if (Datebar.Hour == 10)
if ( Bars.IntradayBarNumber(bar) == 0 )
if (Openbar > daily.Closebar-1)
if (Closebar > Openbar)
if( BuyAtClose(bar) != null )
Stop = daily.Closebar-1;
}
}
} else
DrawLabel( PricePane, "For use on intraday data", Color.Red );
}
}
}
Updating a Daily indicator using Intraday values
Here's how you can update a Daily indicator, say a moving average, recalculating its current value throughout the day using intraday values. This is also valid for backtesting and trading. Run it on intraday data:
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
namespace WealthLab.Strategies
{
public class SMADailyOnIntradayBasis : WealthScript
{
StrategyParameter _period;
public SMADailyOnIntradayBasis()
{
_period = CreateParameter("Period", 20, 1, 100, 1);
}
public int FirstBarofDay(int startDay)
{
int cnt = 0;
int firstBar = Bars.Count;
for (int bar = 0; bar < Bars.Count; bar++)
{
if( Bars.IntradayBarNumber(bar) == 0 ) cnt++;
if( cnt == startDay )
{
firstBar = bar;
break;
}
}
return firstBar;
}
protected override void Execute()
{
SetScaleDaily();
DataSeries dailyCloses = Close;
RestoreScale();
dailyCloses = Synchronize(dailyCloses);
double daySum = 0d;
int db = 0;
bool isInitialized = false;
int per = _period.ValueInt; // number of days for moving average
// the "instantaneous" sma is the sum + Close of the current bar / period
DataSeries sma = new DataSeries(Bars, "Daily SMA on Intraday Basis");
for (int bar = FirstBarofDay(per); bar < Bars.Count; bar++)
{
// On the first bar of the day, sum the previous per - 1 *day values*
if( Bars.IntradayBarNumber(bar) == 0 )
{
daySum = 0d;
int stBar = bar - Bars.IntradayBarNumber(bar); // first bar of current day
for (int n = 1; n < per; n++)
{
stBar--; // last intraday bar of a previous
daySum += dailyClosesstBar;
stBar -= Bars.IntradayBarNumber(stBar); // back to first bar of stBar day
}
}
// Calculate the average for the contribution of the close of this bar
smabar = ( daySum + Closebar ) / per;
}
PlotSeries(PricePane, sma, Color.Blue, LineStyle.Solid, 2);
// Compare it to the pure Daily SMA
SetScaleDaily();
DataSeries smaDay = SMA.Series(Close, per);
RestoreScale();
smaDay = Synchronize(smaDay);
PlotSeries(PricePane, smaDay, Color.Black, LineStyle.Solid, 1);
}
}
}
Selling a position at close at after the 2nd market day after purchasing
Code
Note: Change the
MarketClose constant value for half days.
public class MyStrategy : WealthScript
{
public int GetTime(int bar)
{
return Datebar.Hour * 100 + Datebar.Minute;
}
protected override void Execute()
{
const int MarketClose = 1600;
for(int bar = 20; bar < Bars.Count; bar++)
{
if (IsLastPositionActive)
{
Position p = LastPosition;
if( bar < Bars.Count - 1 )
{
if ( Bars.IsLastBarOfDay( bar+1 ) )
SellAtMarket( bar+1, p, "Mkt On Close" );
else
SellAtStop( bar+1, p, p.EntryPrice * 0.97, "At stop" );
}
// Is last bar of chart the second to the last bar of the day?
else if (GetTime(bar) == MarketClose - Bars.BarInterval)
SellAtMarket( bar+1, p, "Mkt On Close" );
}
else
{
// Entry logic
}
}
}
}