Crashed in OnTick with NullReferenceException: Object reference not set to an instance of an object.

Created at 03 Sep 2020, 01:27
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
MA

maxdelater

Joined 03.09.2020

Crashed in OnTick with NullReferenceException: Object reference not set to an instance of an object.
03 Sep 2020, 01:27


I'm trying to write a cBot, but when I went to backtest it, it came with an error; Crashed in OnTick with NullReferenceException: Object reference not set to an instance of an object.

If it helps, my code is:

using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        #region User defined parameters

        private MacdCrossOver _MACD;
        private SimpleMovingAverage _Sma1;

        [Parameter("Instance Name", DefaultValue = "Harrold")]
        public string InstanceName { get; set; }

        [Parameter("LotSize", DefaultValue = 0.1)]
        public double LotSize { get; set; }

        [Parameter("Period", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Stop Loss", DefaultValue = 20)]
        public int StopLoss { get; set; }
        [Parameter("Take Profit", DefaultValue = 100)]
        public int TakeProfit { get; set; }

        [Parameter("Signal-line crossover true:if Signal-line crossover false: Zero crossover", DefaultValue = true)]
        public bool IsSignalLineCrossover { get; set; }

        [Parameter("Source EMA #1")]
        public DataSeries SourceEma1 { get; set; }

        [Parameter("Source EMA #2")]
        public DataSeries SourceEma2 { get; set; }

        [Parameter("Source EMA #3")]
        public DataSeries SourceEma3 { get; set; }

        [Parameter("Period EMA #1", DefaultValue = 79, MinValue = 1, MaxValue = 200)]
        public int PeriodsEma1 { get; set; }

        [Parameter("Period EMA #2", DefaultValue = 435, MinValue = 1, MaxValue = 500)]
        public int PeriodsEma2 { get; set; }

        [Parameter("Period EMA #3", DefaultValue = 30, MinValue = 1, MaxValue = 200)]
        public int PeriodsEma3 { get; set; }

        [Parameter("Calculate OnBar", DefaultValue = false)]
        public bool CalculateOnBar { get; set; }

        [Parameter("Trailing Stop Step (pips)", DefaultValue = 10)]
        public int TrailingStopStep { get; set; }

        [Parameter("Trailing Stop Trigger (in Pips)", DefaultValue = 10)]
        public int TrailingStopTrigger { get; set; }

        [Parameter("IncludeTrailingStop", DefaultValue = true)]
        public bool IncludeTrailingStop { get; set; }

        [Parameter("Include Break-Even", DefaultValue = true)]
        public bool IncludeBreakEven { get; set; }

        [Parameter("Break-Even Trigger (Pips)", DefaultValue = 5)]
        public int BreakEvenPips { get; set; }

        [Parameter("Break-Even Extra Pips", DefaultValue = 2, MinValue = 1)]
        public int BreakEvenExtraPips { get; set; }

        [Parameter("Source SMA #1")]
        public DataSeries SourceSma1 { get; set; }

        [Parameter("Period SMA #1", DefaultValue = 1)]
        public int PeriodsSma1 { get; set; }

        public double EntryPrice { get; set; }
        public TradeResult TradeResult { get; set; }
        public bool IsSuccesful { get; set; }

        #endregion

        #region Indicator declarations

        private ExponentialMovingAverage _Ema1 { get; set; }
        private ExponentialMovingAverage _Ema2 { get; set; }
        private ExponentialMovingAverage _Ema3 { get; set; }

        #endregion

        #region cTrader events

        /// This is called when the robot first starts, it is only called once.
        protected override void OnStart()
        {
            // construct the indicators
            _Ema1 = Indicators.ExponentialMovingAverage(SourceEma1, PeriodsEma1);
            _Ema2 = Indicators.ExponentialMovingAverage(SourceEma2, PeriodsEma2);
            _Ema3 = Indicators.ExponentialMovingAverage(SourceEma3, PeriodsEma3);
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            _Sma1 = Indicators.SimpleMovingAverage(SourceSma1, PeriodsSma1);
        }

        /// This method is called every time the price changes for the symbol

        protected override void OnTick()
        {
            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }

            if (IncludeBreakEven)
            {
                BreakEvenAdjustment();
            }
        }

        /// This line is called at every candlebar close

        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        #endregion

        #region Position management

        private void ManagePositions()
        {
            #region Open Position

            #region Go Long

            if (_Ema2.Result.Last(1) > _Ema2.Result.Last(2))

                #endregion

                #region Go Short

                if (_Ema2.Result.Last(1) < _Ema2.Result.Last(2))
                {
                    if (_Ema1.Result.Last(1) < _Ema1.Result.Last(2))
                    {
                        if (_Ema3.Result.Last(1) < _Ema3.Result.Last(2))
                        {
                            if (_MACD.MACD.Last(1) > _MACD.Histogram.Last(1))
                            {
                                if (IsSignalLineCrossover)
                                {

                                    if (_MACD.MACD.Last(2) > _MACD.Signal.Last(2) && _MACD.MACD.Last(1) < _MACD.Signal.Last(1))
                                    {
                                        if (!IsPositionOpenByType(TradeType.Sell))
                                        {
                                            OpenPosition(TradeType.Sell);
                                        }

                                        ClosePosition(TradeType.Buy);
                                    }
                                }
                            }
                        }
                    }
                }
            #endregion

            #endregion

            #region Close Position

            #region Close Buy Position

            if (_MACD.MACD.Last(2) > _MACD.Signal.Last(2) && _MACD.MACD.Last(1) < _MACD.Signal.Last(1))
            {
                if (_Sma1.Result.Last(1) > LastResult.Position.EntryPrice)
                {
                    ClosePosition(TradeType.Buy);
                }

                if (_Sma1.Result.Last(1) > LastResult.Position.EntryPrice)
                {
                    if (_Ema1.Result.Last(1) < _Ema1.Result.Last(2))
                    {
                        if (IsPositionOpenByType(TradeType.Buy))
                        {
                            ClosePosition(TradeType.Buy);
                        }
                        else
                        {
                            return;
                        }
                    }
                }
            }
            #endregion

            #region Close Sell Position

            if (_MACD.MACD.Last(2) < _MACD.Signal.Last(2) && _MACD.MACD.Last(1) > _MACD.Signal.Last(1))
            {
                if (_Sma1.Result.Last(1) < LastResult.Position.EntryPrice)
                {
                    ClosePosition(TradeType.Sell);
                }

                if (_Sma1.Result.Last(1) < LastResult.Position.EntryPrice)
                {
                    if (_Ema1.Result.Last(1) > _Ema1.Result.Last(2))
                    {
                        if (IsPositionOpenByType(TradeType.Sell))
                        {
                            ClosePosition(TradeType.Sell);
                        }
                        else
                        {
                            return;
                        }
                    }
                }
            }

            #endregion

            #endregion
        }

        #region Order Execution

        #region Execute Order - Buy
        /// Opens a new long position
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            long volume = Symbol.QuantityToVolume(LotSize);

            // open a new position
            ExecuteMarketOrder(type, this.Symbol, volume, InstanceName, StopLoss, null);
        }
        #endregion

        #region Execute Order _ Sell
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.Symbol, type);

            if (p != null)
            {
                ClosePosition(p);
            }
        }

        #endregion

        #endregion

        #endregion

        #region Position Information

        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, Symbol, type);

            if (p.Count() >= 1)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region Trailing Stop

        /// <summary>
        /// When the profit in pips is above or equal to Trigger the stop loss will start trailing the spot price.
        /// TrailingStop defines the number of pips the Stop Loss trails the spot price by. 
        /// If Trigger is 0 trailing will begin immediately. 
        /// </summary>
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Sell);

            foreach (Position position in sellPositions)
            {
                double distance = position.EntryPrice - Symbol.Ask;

                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Ask + TrailingStopStep * Symbol.PipSize;

                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }
            }

            var buyPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Buy);

            foreach (Position position in buyPositions)
            {
                double distance = Symbol.Bid - position.EntryPrice;

                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Bid - TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }
            }
        }
        #endregion

        #region Break-Even

        /// <summary>
        /// Adjusts the break even plus (x) pips
        /// </summary>
        /// <param name="tradeType"></param>
        private void BreakEvenAdjustment()
        {
            var allPositions = Positions.FindAll(InstanceName, Symbol);

            foreach (Position position in allPositions)
            {
                if (position.StopLoss != null)
                    return;

                var entryPrice = position.EntryPrice;
                var distance = position.TradeType == TradeType.Buy ? Symbol.Bid - entryPrice : entryPrice - Symbol.Ask;

                // move stop loss to break even plus and additional (x) pips
                if (distance >= BreakEvenPips * Symbol.PipSize)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        if (position.StopLoss <= position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for BUY position {0}", position.Id);
                        }
                    }
                    else
                    {
                        if (position.StopLoss >= position.EntryPrice - (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, entryPrice - (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for SELL position {0}", position.Id);
                        }
                    }
                }
            }
        }
        #endregion
    }
}


@maxdelater