Conditional Statements and Control Flow in NinjaTrader 8 Trading Strategies [Lesson 4]

Conditional statements allow you to make decisions in your code based on certain conditions. In NinjaTrader 8, the most commonly used conditional statement is the if statement. Let's start by exploring some smaller examples before we dive into the comprehensive OnBarUpdate method.

Conditional Statements and Control Flow in NinjaTrader 8 Trading Strategies [Lesson 4]

In the previous blog posts, we covered the basics of variable types, logical operators, and expressions in NinjaTrader 8. Now, it's time to explore the power of conditional statements and control flow in your trading strategies and indicators. By leveraging these programming constructs, you can make your strategies more intelligent and responsive to market conditions.

Conditional Statements: Making Decisions

Conditional statements allow you to make decisions in your code based on certain conditions. In NinjaTrader 8, the most commonly used conditional statement is the if statement. Let's start by exploring some smaller examples before we dive into the comprehensive OnBarUpdate method.

Example 1: Simple Condition

bool isMarketOpen = true;

if (isMarketOpen)
{
    Print("The market is open.");
}

In this example, we have a boolean variable isMarketOpen set to true. If the condition isMarketOpen is true, the code block inside the if statement will be executed, and the message "The market is open." will be printed.

Example 2: Condition with Logical Operator

double price = 50.25;

if (price > 50 && price < 60)
{
    Print("The price is within the desired range.");
}

In this example, we check if the price variable is greater than 50 and less than 60. If the condition is true, the code block inside the if statement will be executed, and the message "The price is within the desired range." will be printed.

Example 3: Condition with Else Statement

int num = 15;

if (num > 10)
{
    Print("The number is greater than 10.");
}
else
{
    Print("The number is not greater than 10.");
}

In this example, we check if the num variable is greater than 10. If the condition is true, the code block inside the if statement will be executed, and the message "The number is greater than 10." will be printed. If the condition is false, the code block inside the else statement will be executed, and the message "The number is not greater than 10." will be printed.

These smaller examples demonstrate how conditional statements can be used to make decisions in your code based on specific conditions. Now, let's put everything together and explore a more comprehensive example in the OnBarUpdate method.

protected override void OnBarUpdate()
{
    // Check if there is enough historical data
    if (CurrentBar < 1)
        return;
    
    // Calculate the threshold as a simple moving average of 10 periods
    double threshold = SMA(10)[0];
    
    // Calculate the volume level as a simple moving average of 10 periods using the Volume series
    double volumeLevel = SMA(Volume, 10)[0];

    // Check if the strategy is in the Historical state
    if (State == State.Historical)
    {
        // Check if the current close price is above the threshold and the volume is above the volume level
        if (Close[0] > threshold && Volume[0] > volumeLevel)
        {
            // Output a message indicating that the condition is met in the Historical state
            Print("Historical - " + Time[0] + " - Condition met: Price is above threshold and volume is above level.");
        }
        else
        {
            // Output a message indicating that the condition is not met in the Historical state
            Print("Historical - " + Time[0] + " - Condition not met: Price is below threshold or volume is below level.");
        }
    }
    // Check if the strategy is in the Realtime state
    else if (State == State.Realtime)
    {
        // Check if the current close price is below the threshold or the volume is below the volume level
        if (Close[0] < threshold || Volume[0] < volumeLevel)
        {
            // Output a message indicating that the condition is met in the Realtime state
            Print("Realtime - " + Time[0] + " - Condition met: Price is below threshold or volume is below level.");
        }
        else
        {
            // Output a message indicating that the condition is not met in the Realtime state
            Print("Realtime - " + Time[0] + " - Condition not met: Price is above threshold and volume is above level.");
        }
    }
}

Control Flow: Guiding Program Execution

Control flow allows you to control the execution of your program by specifying the order and conditions under which different sections of code are executed. In NinjaTrader 8, control flow is often achieved using conditional statements, loops, and other constructs.

Let's consider an example where we want to execute a specific block of code only during market hours:

if (Time[0].TimeOfDay >= new TimeSpan(9, 30, 0) && Time[0].TimeOfDay <= new TimeSpan(16, 0, 0))
{
    // Code to be executed during market hours
}

In this snippet, we use the Time series to retrieve the current time and check if it falls within the desired market hours. If the condition is true, the specified code block will be executed.

Download the Example Code: If you'd like to experiment with the examples provided above, you can download the code using the button below and import the NinjaScript add-on into NinjaTrader 8.

Implementing Loops for Iterative Processes and Dynamic Decision-Making

Let's take our understanding a step further and dive into implementing loops for iterative processes and dynamic decision-making.

One practical example where loops can be incredibly useful is when calculating the average price over a specific number of bars. Suppose we want to calculate the average price over the last 10 bars. Manually summing the prices for each bar and dividing by 10 would be cumbersome and difficult to maintain. This is where loops come to the rescue.

Instead of hardcoding individual bar prices, we can leverage loops to iterate through the desired number of bars and calculate the average dynamically. Let's take a look at how this can be achieved:

double sum = 0;
int numBars = 10;

for (int i = 0; i < numBars; i++)
{
    sum += Close[i];
}

double averagePrice = sum / numBars;

In this example, we use a "for" loop to iterate from 0 to numBars - 1 and sum up the closing prices of each bar. By dividing the sum by numBars, we obtain the average price over the specified number of bars.

By implementing loops, we make the code more efficient, maintainable, and scalable. Instead of repeating code for each individual bar, we utilize the power of loops to handle repetitive tasks in a concise and dynamic manner.

Loops are not limited to simple summations; they can be utilized for a wide range of iterative processes within trading strategies and indicators. For example, you can iterate through historical data to identify specific patterns, calculate indicators, or perform complex calculations.

By combining looping structures with conditional statements, traders can create intricate and adaptive trading strategies. Conditional statements within loops allow for dynamic decision-making based on specific criteria, enabling the strategy to adjust its behaviour as market conditions evolve.

For instance, you can incorporate an "if" statement within a loop to perform different actions based on certain conditions. This allows for real-time monitoring and decision-making within the loop, ensuring that the strategy adapts to changing market dynamics.

for (int i = 0; i < numBars; i++)
{
    if (Close[i] > Open[i])
    {
        // Code to execute when the condition is met
        Print("Bullish bar at index " + i);
    }
    else
    {
        // Code to execute when the condition is not met
        Print("Bearish bar at index " + i);
    }
}

In this example, the loop iterates through historical bar data, and the "if" statement within the loop checks whether the current bar is bullish or bearish. Depending on the condition, the appropriate code block is executed.

By leveraging looping structures and conditional statements, traders can create trading strategies that dynamically respond to changing market conditions, make informed decisions, and adapt their trading logic as needed.

Remember to consider factors such as loop efficiency, data handling, and avoiding infinite loops when implementing looping structures in your trading strategies. Optimizing loop performance and ensuring appropriate data management are essential for maintaining the efficiency and reliability of your strategies. Also, make sure to check that you have enough bars when looping.

Flexible Looping with the 'while' Loop: Iteration and Condition-Based Execution

In addition to the "for" loop, NinjaTrader 8 (C#) also provides other looping structures, such as the "while" loop. The "while" loop continues executing as long as a specified condition remains true. This offers flexibility in implementing dynamic decision-making within the loop.

int counter = 0;
while (counter < 10)
{
    Print("Counter: " + counter);
    counter++;
}

In this example, the "while" loop will continue executing as long as the counter is less than 10. The code block inside the loop prints the current value of the counter and increments it by 1 with each iteration.

Conclusion

In this blog post, we delved into conditional statements and control flow in NinjaTrader 8 trading strategies and indicators. We explored practical examples of conditional statements using the if statement and discussed how control flow allows you to guide the execution of your program. Additionally, we explored the power of loops, enabling iterative processes and dynamic decision-making within your strategies.

By combining conditional statements, loops, and other control flow constructs with variable types, operators, and expressions, you can create sophisticated and adaptable trading strategies and indicators in NinjaTrader 8.