Confusion with Dates

Some input on using dates would be appreciated. I'm working on a rotational strategy (I've used both the AmiBroker rotation method and just general method of strategy creation). Question I have is around dates executing properly.

I essentially would like to stay in positions for at least X number of days but have it exit as close as possible to a certain day of the month (BuyDayofMonth). Any suggestions for code improvements would be much appreciated. If I'm using 28 as the BuyDayofMonth, I'd like to get out the next month as close to the 28th as possible.

I'm currently using the following... I'm getting average exit days in the range I want but several get out 3 or so days earlier than I'd like. Thank you.

BuyDayofMonth = param("Buy Day of Month", 28, 1, 31, 1); // 15, 28, 30 -- 16, 23, 25, 29, 24, 21, 20, 9, 22, 26, 17, 1, 28

PositionScore = whatever;

Buy = Day() >= BuyDayofMonth AND Day() <= BuyDayofMonth + 2;

Sell = BarsSince(Buy) > 16 AND BarsSince(Buy) < 23 AND Day() <= BuyDayofMonth +2 ;

You seem to use "days" and "bars" interchangeably. Please keep in mind that "bars" are not "days". "bars" are trading days, excluding Sundays and Saturdays. BarsSince gives you bars, while Day() gives you calendar days.

3 Likes

Here is some code I've used in the past to identify the first day on or after the target day of the month. You could modify this logic a bit to get the first day or or before the target day. To @Tomasz' point, this code assumes you are operating on daily bars.

rotationDay = 15;        // Day of the month, 1-28
mth = Month();
dayOfMonth = Day();

// Today is a rotation day if it's the first day on or after the rotation day of month, and the
// previous day was either an earlier day of the month or the end of the previous month
isRotDay = dayOfMonth >= rotationDay AND
		    (mth != Ref(mth,-1) OR Ref(dayOfMonth,-1) < rotationDay1);

3 Likes

I think that did it Matt, much obliged! :smiley:

Regards,

Dave

Matt,

I modified the code a little as my strategy was skipping over Feb trades each year and giving me 11 rotations per year instead of 12. I limited the total number of trading days per month to 22 also because of data and date issues with some of the exits, it would sometimes not get out of a trade and therefore stay in a few "anomalous" trades for over 40 days (2 months or so) when it would miss the exit day. Here's my modified code... thanks again!

rotationDay = param("Rotation Day of Month", 28, 1, 31, 1);
rotationDayFeb = Param("Rotation Day for Feb", 26, 1, 31, 1);

mth = Month();
dayOfMonth = Day();

isRotDay = dayOfMonth >= rotationDay AND (mth != Ref(mth,-1) OR Ref(dayOfMonth,-1) < rotationDay);
isRotDayFeb = dayOfMonth >= rotationDayFeb AND (mth != Ref(mth,-1) OR Ref(dayOfMonth,-1) < rotationDayFeb); 

Buy = IIf(mth == 2, dayOfMonth >= rotationDayFeb AND Ref(dayOfMonth,-1) < rotationDayFeb, dayOfMonth >= rotationDay AND Ref(dayOfMonth,-1) < rotationDay);
Sell = IIf(mth == 2, isRotDayFeb OR BarsSince(Buy) >= 22, isRotDay OR BarsSince(buy) >= 22);

3 Likes

@DaveDM instead of "calendar dates" have you considered using trading day of the month (which if using Daily bars is Trading Bar of the month)? Like calendar dates it will vary from month to month (past few years 19-23 trading days per month in North American markets).

Many ways to code a count of days or a specific day, here are some examples.

// Counting the actual Trading Days each month
// And just for an example exploring for the 1st trading day 
// in any given month

TradingDayThisMonth = BarsSince( Day() < Ref(Day(),-1) ) + 1;

FirstDay = TradingDayThisMonth==1;

// in AmiBroker there are many ways to arrive at the same endpoint
// the following code arrives at the same result as the above code

alternateCode = BarsSince(Month() != Ref( Month(), -1) )+1;

// another interesting day is often the first trading day of the month
isFirstOfMonth = Month() != Ref(Month(),-1);

// another method looking at Last trading day of month
LastDayOfMonth = TimeframeExpand(1, inMonthly, expandPoint);

Filter=1;
AddColumn(TradingDayThisMonth, "TradingDayThisMonth", 1.0);
AddColumn(alternateCode, "alternateCode", 1.0);
AddColumn( FirstDay,"First Day",1,colorBlue, IIf(FirstDay, colorYellow,colorDefault));
AddColumn( isFirstOfMonth,"another First Day", 1,colorWhite, IIf(isFirstOfMonth, colorBlue,colorDefault));
AddColumn(LastDayOfMonth, "Last Day", 1.0, colorWhite, IIf(LastDayOfMonth, colorRed, colorDefault));

A debugging Explore produces these types of result,
image

8 Likes

@DaveDM: You're correct that this logic did not work consistently when defining a rotation day very close to the end of the month. I originally wrote it for use near the beginning or middle of each month. EOM logic would work better if we chose a day less than or equal to the rotation day rather than greater than or equal to the rotation day.

Glad that you got your solution working. You could probably use isRotDay and isRotDayFeb inside your Buy= assignment rather than repeating all that logic.

@portfoliobuilder: Good idea regarding using the trading day of the month rather than the calendar day.

2 Likes

@portfoliobuilder ... and this is why we need you in our AmiBroker group :wink: Thanks a bunch!,

Dave

2 Likes

Does anyone have a concise function for BarsTillEndOfTheMonth?

Utilizing historical EOD database would be the easiest, I just can't think of doing it right now without finding end of the month as above
isEndOfMonth = TimeFrameExpand(1,inMonthly,expandPoint);
and then checking 23 times (there are up to 23 bars or trading days in a month) which day it is until then. I'd like for it to return an integer, positive or negative, with how many bars from current date until end of the month.

Trading bars remaining in the month or Calendar days remaining in the month?

Bars (or trading days, until the end of the month). EOD db already accounts for weekends and holidays.

Here is a live EOD (non historical) version that you could modify to suit.

// Calculate live EOD remaining trading days in the month (does not include public holidays that fall in the rest of the month)

monthlyDateDiff = DateTimeAdd(DateTime(), 1, inMonthly);
monthlyDateDiff = DateTimeDiff(monthlyDateDiff, DateTime()) / 60 / 60 / 24;
daysRemaining = LastValue(monthlyDateDiff - Day());

lastDow = LastValue(DayOfWeek());
nonTradingDaysRemaining = 0;

for( i = 1; i <= daysRemaining; i++ )
{
	lastDow++;
	
	if (lastDow > 6)
	{
		nonTradingDaysRemaining++;
		lastDow = 0;
	}
	else if (lastDow == 6) nonTradingDaysRemaining++;
}

tradingDaysRemaining = daysRemaining - nonTradingDaysRemaining;

Filter = Status("LastBarInRange");

AddColumn(daysRemaining, "Calendar Days Remaining (Month)", 1);
AddColumn(nonTradingDaysRemaining, "Non-Trading Days Remaining (Month)", 1);
AddColumn(tradingDaysRemaining, "Trading Days Remaining (Month)", 1);

image

6 Likes

Thank you very much, @ TrendSurfer!

1 Like