'Quantower API: How to get the current and previous bar's Low price

Goal:

On a 1 minute candlechart using the Quantower API, to get the previous bar's low price, and the current bar's open, high and low price to be used in a strategy (not an indicator template).

Issues:

With the code below, cannot manage to retrieve the prices mentioned above. In an indicator template this seems to be simple enough, however, in a strategy template these prices are not returned (having tested this by printing them to the log output in the debugger). Before asking this question, the Quantower API Github has been consulted to try to use code from the examples found here and here, as well as the Quantower documentation for downloading history found here.

Code attempt:

The attempts to get current bar and previous bar's prices can be seen below in the function SymbolOnNewLast( Symbol symbol, Last last ):

    using System;
    using System.Collections.Generic;
    using TradingPlatform.BusinessLayer;
    
    namespace test6
    {
        public class test6 : Strategy
        {
            [InputParameter("Symbol", 10)]
            private Symbol symbol;
    
            [InputParameter("Account", 20)]
            public Account account;
    
            [InputParameter("Quantity", 20)]
            public double quantity;
    
            public override string[] MonitoringConnectionsIds => new string[] { this.symbol?.ConnectionId };
    
            public test6()
                : base()
            {
                // Defines strategy's name and description.
                this.Name = "test6";
                this.Description = "My strategy's annotation";
            }
    
            protected override void OnCreated()
            {
                // Add your code here
            }
    
            protected override void OnRun()
            {
                if (symbol == null || account == null || symbol.ConnectionId != account.ConnectionId)
                {
                    Log("Incorrect input parameters... Symbol or Account are not specified or they have diffent connectionID.", StrategyLoggingLevel.Error);
                    return;
                }
    
                this.symbol = Core.GetSymbol(this.symbol?.CreateInfo());
    
                if (this.symbol != null)
                {
                    this.symbol.NewQuote += SymbolOnNewQuote;
                    this.symbol.NewLast += SymbolOnNewLast;
                }
    
                // Add your code here
            }

            protected override void OnStop()
            {
                if (this.symbol != null)
                {
                    this.symbol.NewQuote -= SymbolOnNewQuote;
                    this.symbol.NewLast -= SymbolOnNewLast;
                }
    
                // Add your code here
            }
    
            protected override void OnRemove()
            {
                this.symbol = null;
                this.account = null;
                // Add your code here
            }
    
            protected override List<StrategyMetric> OnGetMetrics()
            {
                List<StrategyMetric> result = base.OnGetMetrics();
    
                return result;
            }
    
            private void SymbolOnNewQuote(Symbol symbol, Quote quote)
            {
                // Add your code here
            }
    
            private void SymbolOnNewLast(Symbol symbol, Last last)
            {
                // Get current and previous bar price data
                HistoricalData historicalData = symbol.GetHistory(Period.MIN1, DateTime.UtcNow.AddDays(-1));
    
                double prevLow = ((HistoryItemBar)historicalData[1]).Low;    // Get PREVIOUS bar low
                double openPrice = ((HistoryItemBar)historicalData[0]).Open;   // Get CURRENT  bar open
                double closePrice = ((HistoryItemBar)historicalData[0]).Close;  // Get CURRENT  bar close
    
                // If CURRENT bar open price MORE than CURRENT bar close price:
                if (openPrice > closePrice)
                {
                    // execute some action
                }
            }
        }
    }

Questions:

Q1. How can the current bar and previous bars different prices (for example: Open, High, Low, Close etc) be retrieved within a Quantower API strategy template?



Solution 1:[1]

We can add the function "M1HistoryBarUpdate(object sender, HistoryEventArgs e)" so that the quantower will automatically handle this issue when minute 1 data updates. To this end, we remove the it in the OnRemove() function to release memory.

Below is the sample code for updating minute 1 and minute 2 bar. Therefore, we can get the history data in the StrategyProcess() function, and code your trading logic here.

using System;
using System.Linq;
using System.Collections.Generic;
using TradingPlatform.BusinessLayer;

namespace Test_New_Bar_Arrive
{

public class Test_New_Bar_Arrive : Strategy
{
    [InputParameter("Symbol", 10)]
    private Symbol symbol;

    [InputParameter("Account", 20)]
    public Account account;

    [InputParameter("BarCountPreprocess")]

    private HistoricalData m1BarHistory; // Declare M1 history handler
    private HistoricalData m2BarHistory; //  Declare M2 history handler

    public override string[] MonitoringConnectionsIds => new string[] { this.symbol?.ConnectionId };

    public Test_New_Bar_Arrive()
        : base()
    {
        // Defines strategy's name and description.
        this.Name = "Test_New_Bar_Arrive";
        this.Description = "My strategy's annotation";
    }

    /// <summary>
    /// This function will be called after creating a strategy
    /// </summary>
    protected override void OnCreated()
    {
        // Add your code here
    }

    /// <summary>
    /// This function will be called after running a strategy
    /// </summary>
    protected override void OnRun()
    {
        if (symbol == null || account == null || symbol.ConnectionId != account.ConnectionId)
        {
            Log("Incorrect input parameters... Symbol or Account are not specified or they have diffent connectionID.", StrategyLoggingLevel.Error);
            return;
        }

        this.symbol = Core.GetSymbol(this.symbol?.CreateInfo());

        if (this.symbol != null)
        {
            this.symbol.NewQuote += SymbolOnNewQuote;
            this.symbol.NewLast += SymbolOnNewLast;
        }

        // Add your code here
        m1BarHistory = symbol.GetHistory(Period.MIN1, Core.TimeUtils.DateTimeUtcNow); // Add the history handler for minute 1 bar
        m2BarHistory = symbol.GetHistory(Period.MIN2, Core.TimeUtils.DateTimeUtcNow); // Add the history handler for minute 2 bar

        m1BarHistory.NewHistoryItem += this.M1HistoryBarUpdate; // Update when the history data changes
        m2BarHistory.NewHistoryItem += this.M2HistoryBarUpdate; // Update when the history data changes

    }

    private void M1HistoryBarUpdate(object sender, HistoryEventArgs e)
    {
        Log("M1 Bar Updating"); // Log the result, when minute 1 bar updates
        StrategyProcess(this.symbol); // Code your strategy here
    }

    private void M2HistoryBarUpdate(object sender, HistoryEventArgs e)
    {
        Log("M2 Bar Updating"); // Log the result, when minute 2 bar updates
    }

    private void StrategyProcess(Symbol symbol)
    {
        
        HistoricalData m1Data = symbol.GetHistory(Period.MIN1, symbol.HistoryType, DateTime.UtcNow.AddMinutes(-5)); // Get the history bars for previous five minutes
        double newFixingBarClose = ((HistoryItemBar) m1Data[0]).Close; // This is the latest minute 1 bar's close price.
        DateTime newFixingBarEndTime = ((HistoryItemBar)m1Data[0]).TimeRight; // This is the latest minute 1 bar's ending time 
        Log("M1 Time[0] :: " + newFixingBarEndTime.ToString() + "__Close[0] ::" + newFixingBarClose.ToString()); 
    }
    /// <summary>
    /// This function will be called after stopping a strategy
    /// </summary>
    protected override void OnStop()
    {
        if (this.symbol != null)
        {
            this.symbol.NewQuote -= SymbolOnNewQuote;
            this.symbol.NewLast -= SymbolOnNewLast;
        }

        // Add your code here
        m1BarHistory.NewHistoryItem -= this.M1HistoryBarUpdate;
        m2BarHistory.NewHistoryItem -= this.M2HistoryBarUpdate;
    }

    /// <summary>
    /// This function will be called after removing a strategy
    /// </summary>
    protected override void OnRemove()
    {
        this.symbol = null;
        this.account = null;

        // Add your code here
        if (m1BarHistory != null)
        {
            m1BarHistory.Dispose();
        }
        if (m2BarHistory != null)
        {
            m2BarHistory.Dispose();
        }
    }

    /// <summary>
    /// Use this method to provide run time information about your strategy. You will see it in StrategyRunner panel in trading terminal
    /// </summary>
    protected override List<StrategyMetric> OnGetMetrics()
    {
        List<StrategyMetric> result = base.OnGetMetrics();

        // An example of adding custom strategy metrics:
        // result.Add("Opened buy orders", "2");
        // result.Add("Opened sell orders", "7");

        return result;
    }

    private void SymbolOnNewQuote(Symbol symbol, Quote quote)
    {
        // Add your code here
    }

    private void SymbolOnNewLast(Symbol symbol, Last last)
    {
        // Add your code here       
    }

}
}

Solution 2:[2]

@Xiang

It seems like StrategyProcess never reaches line

Log("M1 Time[0] :: " + newFixingBarEndTime.ToString() + "__Close[0] ::" + newFixingBarClose.ToString()); 

This line is never printed...I was able to confirm that StrategyProcess is entered by logging information right before HistoricalData m1Data executes.

Any idea what's going on?

Solution 3:[3]

@WhyNotCode

Sorry. I don't have the right to add comment below your question, and I make it here.

I execute the code again, and this still works fine for me.

To my best knowledge, if you have some error codes in Visual studio, you still can compile the project and run it on the StrategyRunner. However, Quantower will automatically neglect all of your after reaching the error part. For example, if you have error before Log("?") function, you still can run strategy, but Log("?") will not be executed.

Maybe you can check your code again. Hope this information helps you. enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 WhyNotCode
Solution 3