Situation
You only want to trade a strategy during certain time periods, for example a day session from 9:00 till 15:00 or an overnight session from 22:00 till 6:00.

Programming code

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using ATCenterProxy.interop;

namespace PowerLanguage.Strategy
{
    public class Example_TradeDuringCertainTimes : SignalObject
    {
        private IOrderMarket buyOrder, sellOrder;
        private TimeSpan startTime, endTime;

        [Input]
        public string StartTime { get; set; }

        [Input]
        public string EndTime { get; set; }

        public Example_TradeDuringCertainTimes(object _ctx) : base(_ctx) { }

        protected override void Create()
        {
            // Assign a default value
            StartTime = "8:00";
            EndTime = "20:00";

            buyOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default,
                EOrderAction.Buy));
            sellOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default,
                EOrderAction.Sell));
        }

        protected override void StartCalc()
        {
            // Convert the input string times to TimeSpan format
            startTime = ConvertToTime(StartTime);
            endTime = ConvertToTime(EndTime);
        }

        protected override void CalcBar()
        {
            // If the current bar time falls outside the time range, return control
            if (!TimeToTrade())
            {
                // Close any position that is still open
                if (StrategyInfo.MarketPosition > 0)
                    sellOrder.Send();

                return;
            }

            // Enter a long position
            if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 2 == 0))
                buyOrder.Send();

            // Exit long position
            if ((StrategyInfo.MarketPosition > 0) && (Bars.CurrentBar % 10 == 0))
                sellOrder.Send();
        }

        // The ConvertToTime() method converts a string to a TimeSpan structure.
        private TimeSpan ConvertToTime(string timeToConvert)
        {
            DateTime dt = DateTime.ParseExact(timeToConvert, "H:mm",
                System.Globalization.CultureInfo.InvariantCulture);

            return dt.TimeOfDay;
        }

        // The TimeToTrade() method returns 'true' if the current bar
        // time falls within the trading hours range, or else returns 'false'.
        private bool TimeToTrade()
        {
            TimeSpan barTime = Bars.TimeValue.TimeOfDay;

            // If the range is on the same day, both expressions must be true
            if (startTime < endTime)
                return (barTime >= startTime) && (barTime <= endTime);

            // Otherwise the range crosses midnight, and only one of
            // the expressions need to be true
            return (barTime > startTime) || (barTime < endTime);
        }
    }
}

MultiCharts .NET programming example

For the start and end times the example uses C#’s TimeSpan. A TimeSpan represents an interval of time measured as a positive or negative number of days, hours, minutes, seconds, and fractions of a second (Dorman, 2010). However, a TimeSpan structure can not be used directly as a strategy input in MultiCharts .NET. Therefore we use two strings (lines 14-18) which are later converted to the TimeSpan structure.

In the Create() method, the StartTime and EndTime strings are assigned a default value and the orders are initialized:

protected override void Create()
{
    // Assign a default value
    StartTime = "8:00";
    EndTime = "20:00";

    buyOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default,
        EOrderAction.Buy));
    sellOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default,
        EOrderAction.Sell));
}

Then in the StartCalc() method the strings are converted:

protected override void StartCalc()
{
    // Convert the input string times to TimeSpan format
    startTime = ConvertToTime(StartTime);
    endTime = ConvertToTime(EndTime);
}

See the article the override methods for processing price data to learn more about these methods, and to learn why the conversion is done in the StartCalc() method and not in the Create() method.

Converting a string to a TimeSpan time interval

The actual conversion is done by the method ConvertToTime(), which is implemented as follows:

// The ConvertToTime() method converts a string to a TimeSpan structure.
private TimeSpan ConvertToTime(string timeToConvert)
{
    DateTime dt = DateTime.ParseExact(timeToConvert, "H:mm",
        System.Globalization.CultureInfo.InvariantCulture);

    return dt.TimeOfDay;
}

This method accepts a string as a parameter, which is converted to DateTime with the ParseExact() method. ParseExact() takes three parameters: the string with the time to convert, the type of time formatting used in that string, and information about the culture so that the time is processed correctly. This last parameter is set to culture-independent (invariant) here since we don’t need to convert a culture-specific format. After this conversion, the ConvertToTime() method returns the TimeSpan structure of the DateTime structure.

Note that the time format specifier in this example is H:mm, meaning the hour without leading zero for a 24 hour clock (0 to 23) and mm for the minute with a leading zero (00 to 59). If you want to specify the time in a different way, the format specifier needs to be changed. Change it for example to H:mm:ss if you want to include seconds.

Only trade during certain times in MultiCharts .NET

Moving on to the CalcBar() method, we see that another custom method is called:

protected override void CalcBar()
{
    // If the current bar time falls outside the time range, return control
    if (!TimeToTrade())
    {
        // Close any position that is still open
        if (StrategyInfo.MarketPosition > 0)
            sellOrder.Send();

        return;
    }

    // Enter a long position
    if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 2 == 0))
        buyOrder.Send();

    // Exit long position
    if ((StrategyInfo.MarketPosition > 0) && (Bars.CurrentBar % 10 == 0))
        sellOrder.Send();
}

The TimeToTrade() method returns a Boolean value which is true when the current bar time is in the trading hours range defined by the start and end time. When this is condition is false, checked with the ! not logical operator in the if statement, sell orders are send for any open long position and the return statement is called. That statement ensures that all remaining code in the CalcBar() method is not executed since it returns control to the calling method.

The TimeToTrade() method is implemented as follows:

// The TimeToTrade() method returns 'true' if the current bar
// time falls within the trading hours range, or else returns 'false'.
private bool TimeToTrade()
{
    TimeSpan barTime = Bars.TimeValue.TimeOfDay;

    // If the range is on the same day, both expressions must be true
    if (startTime < endTime)
        return (barTime >= startTime) && (barTime <= endTime);

    // Otherwise the range crosses midnight, and only one of
    // the expressions need to be true
    return (barTime > startTime) || (barTime < endTime);
}

The current time of the bar (Bars.TimeValue.TimeOfDay) is saved to a variable for easy referencing. The if statement checks to see if the time range is on the same day and, if that is the case, returns the result of evaluating the accompanying expressions. If the time range is not on the same day, by definition it has to cross midnight. For that situation the last line of the method returns the relevant expressions.

Finally, to wrap up our discussion of this programming example, in the last part of the CalcBar() method (lines 53-59) buy and sell orders are generated based on the bar number with the C# modulus operator.

References

Dorman, S. (2010). Sams Teach Yourself Visual C# 2010 in 24 Hours. Indianapolis, IN (USA): Sams/Pearson Education.