Troubleshooting a cBot for trading the WMA price Crosses

Created at 13 Apr 2019, 10:31
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!
PE

pejman101

Joined 12.04.2019

Troubleshooting a cBot for trading the WMA price Crosses
13 Apr 2019, 10:31


Hello and good day everyone

I've borrowed a code from clickalgo education section that was originally designed to trade by MA crosses and modified it to operate when the price crosses the WMA so it would trade with only one WMA but i'm getting some errors and the code doesn't compile

The original code:

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;


/*
 *  POPULAR SIMPLE MOVING AVERAGES
 *
 *  The simple moving average (SMA) is the most basic of the moving averages used for trading. 
 *  The simple moving average formula is calculated by taking the average closing price of a stock over the last "x" periods.
 *  
 *  5 - SMA  - For the hyper trader.  This short of an SMA will constantly give you signals.  The best use of a 5-SMA is as a trade trigger in conjunction with a longer SMA period.
 *  10 - SMA - popular with the short-term traders.  Great swing traders and day traders.
 *  20 - SMA - the last stop on the bus for short-term traders.  Beyond 20-SMA you are basically looking at primary trends.
 *  50 - SMA - use the trader to gauge mid-term trends.
 *  200 -SMA - welcome to the world of long-term trend followers.  Most investors will look for a cross above or below this average to represent if the stock is in a bullish or bearish trend.
 *  
 */

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

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

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

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

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

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

        [Parameter("Period SMA #2", DefaultValue = 20, MinValue = 1, MaxValue = 100)]
        public int PeriodsSma2 { get; set; }

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

        [Parameter("Include Trailing Stop", DefaultValue = false)]
        public bool IncludeTrailingStop { get; set; }

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

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

        #endregion

        #region Indicator declarations

        private SimpleMovingAverage _sma1 { get; set; }
        private SimpleMovingAverage _sma2 { get; set; }

        #endregion

        #region cTrader events

        /// <summary>
        /// This is called when the robot first starts, it is only called once.
        /// </summary>
        protected override void OnStart()
        {
            // construct the indicators
            _sma1 = Indicators.SimpleMovingAverage(SourceSma1, PeriodsSma1);
            _sma2 = Indicators.SimpleMovingAverage(SourceSma2, PeriodsSma2);
        }

        /// <summary>
        /// This method is called every time the price changes for the symbol
        /// </summary>
        protected override void OnTick()
        {
            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        /// <summary>
        /// This method is called at every candle (bar) close, when it has formed
        /// </summary>
        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        /// <summary>
        /// This method is called when your robot stops, can be used to clean-up memory resources.
        /// </summary>
        protected override void OnStop()
        {
            // unused
        }

        #endregion

        #region Position management

        private void ManagePositions()
        {
            if (_sma1.Result.LastValue > _sma2.Result.LastValue)
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                }

                ClosePosition(TradeType.Sell);
            }

            // if a sell position is already open and signal is buy do nothing
            if (_sma1.Result.LastValue < _sma2.Result.LastValue)
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    OpenPosition(TradeType.Sell);
                }

                ClosePosition(TradeType.Buy);
            }
        }

        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            long volume = Symbol.QuantityToVolume(LotSize);

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

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.Symbol, type);

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

        /// <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 Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, Symbol, type);

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

            return false;
        }

        #endregion
    }
}

My code:

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

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

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

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

        [Parameter("Source")]
        public DataSeries Sourcewma { get; set; }

        [Parameter("Period", DefaultValue = 1, MinValue = 1, MaxValue = 1000)]
        public int Periodwma { get; set; }

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

        [Parameter("Take Profit", DefaultValue = null, MinValue = null, Step = 1)]
        public double TakeP { get; set; }

        [Parameter("Stop Loss", DefaultValue = null, MaxValue = null, Step = 1)]
        public double StopL { get; set; }
        
        [Parameter("Include Trailing Stop", DefaultValue = false)]
        public bool IncludeTrailingStop { get; set; }

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

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

        #endregion

        #region Indicator declarations

        private WeightedMovingAverage { get; set; }

        #endregion

        #region cTrader events

        /// <summary>
        /// This is called when the robot first starts, it is only called once.
        /// </summary>
        protected override void OnStart()
        {
            // construct the indicators
            wma = Indicators.WeightedMovingAverage(Sourcewma, Periodswma);
        }

        /// <summary>
        /// This method is called every time the price changes for the symbol
        /// </summary>
        protected override void OnTick()
        {
            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        /// <summary>
        /// This method is called at every candle (bar) close, when it has formed
        /// </summary>
        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        /// <summary>
        /// This method is called when your robot stops, can be used to clean-up memory resources.
        /// </summary>
        protected override void OnStop()
        {
            // unused
        }

        #endregion

        #region Position management

        private void ManagePositions()
        {
            if (wma.Result.LastValue.HasCrossedAbove)
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                }

                ClosePosition(TradeType.Sell);
            }

            // if a sell position is already open and signal is buy do nothing
            if (wma.Result.LastValue.HasCrossedBelow)
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    OpenPosition(TradeType.Sell);
                }

                ClosePosition(TradeType.Buy);
            }
        }

        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            long volume = Symbol.QuantityToVolume(LotSize);

            // open a new position
            ExecuteMarketOrder(type, this.Symbol, volume, InstanceName, StopL, Take);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.Symbol, type);

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

        /// <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 Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, Symbol, type);

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

            return false;
        }

        #endregion
    }
}

I was wondering if anyone can help me find out what am I doing wrong

Best regards


@pejman101
Replies

2bnnp
13 Apr 2019, 13:49

Line 49:

private WeightedMovingAverage wma { get; set; }

I would recommend using a underscore as prefix for private variables (_wma)

Theres also a typo in line 61/25 and 143. 

 

And well line 109/121, you need to tell the wma what variable it should check for if it crossed above, in your case the close.

        private void ManagePositions()
        {
            double close = MarketSeries.Close.LastValue;
            if (wma.Result.HasCrossedAbove(close,0))
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                }

                ClosePosition(TradeType.Sell);
            }

            // if a sell position is already open and signal is buy do nothing
            if (wma.Result.HasCrossedBelow(close,0))
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    OpenPosition(TradeType.Sell);
                }

                ClosePosition(TradeType.Buy);
            }
        }

 


@2bnnp

pejman101
13 Apr 2019, 18:41

RE:

2bnnp said:

Line 49:

private WeightedMovingAverage wma { get; set; }

I would recommend using a underscore as prefix for private variables (_wma)

Theres also a typo in line 61/25 and 143. 

 

And well line 109/121, you need to tell the wma what variable it should check for if it crossed above, in your case the close.

        private void ManagePositions()
        {
            double close = MarketSeries.Close.LastValue;
            if (wma.Result.HasCrossedAbove(close,0))
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                }

                ClosePosition(TradeType.Sell);
            }

            // if a sell position is already open and signal is buy do nothing
            if (wma.Result.HasCrossedBelow(close,0))
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    OpenPosition(TradeType.Sell);
                }

                ClosePosition(TradeType.Buy);
            }
        }

 

Thank you very much for your help,thanks to you almost all of the errors got sloved but i'm still having 4 errors in line 110/122

This is the new code: 

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

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

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

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

        [Parameter("Source")]
        public DataSeries Sourcewma { get; set; }

        [Parameter("Period", DefaultValue = 1, MinValue = 1, MaxValue = 1000)]
        public int Periodwma { get; set; }

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

        [Parameter("Take Profit", DefaultValue = null, MinValue = null, Step = 1)]
        public double TakeP { get; set; }

        [Parameter("Stop Loss", DefaultValue = null, MaxValue = null, Step = 1)]
        public double StopL { get; set; }
        
        [Parameter("Include Trailing Stop", DefaultValue = false)]
        public bool IncludeTrailingStop { get; set; }

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

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

        #endregion

        #region Indicator declarations

        private  WeightedMovingAverage _wma { get; set; }
        
    #endregion

    #region cTrader events

    /// <summary>
    /// This is called when the robot first starts, it is only called once.
    /// </summary>
    protected override void OnStart()
        {
            // construct the indicators
            _wma = Indicators.WeightedMovingAverage(Sourcewma, Periodwma);
        }

        /// <summary>
        /// This method is called every time the price changes for the symbol
        /// </summary>
        protected override void OnTick()
        {
            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        /// <summary>
        /// This method is called at every candle (bar) close, when it has formed
        /// </summary>
        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        /// <summary>
        /// This method is called when your robot stops, can be used to clean-up memory resources.
        /// </summary>
        protected override void OnStop()
        {
            // unused
        }

        #endregion

        #region Position management

        private void ManagePositions()
        {
            double close = MarketSeries.Close.LastValue;
            if (_wma.Result.LastValue.HasCrossedAbove(close,0))
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                }

                ClosePosition(TradeType.Sell);
            }

            // if a sell position is already open and signal is buy do nothing
            if (_wma.Result.LastValue.HasCrossedBelow(close, 0))
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    OpenPosition(TradeType.Sell);
                }

                ClosePosition(TradeType.Buy);
            }
        }

        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            long volume = Symbol.QuantityToVolume(LotSize);

            // open a new position
            ExecuteMarketOrder(type, this.Symbol, volume, InstanceName, StopL, TakeP);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.Symbol, type);

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

        /// <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 Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, Symbol, type);

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

            return false;
        }

        #endregion
    }
}

 


@pejman101

2bnnp
13 Apr 2019, 20:54

if (_wma.Result.LastValue.HasCrossedAbove(close,0))

is wrong, it needs to be

if (_wma.Result.HasCrossedAbove(close,0))

 


@2bnnp

pejman101
13 Apr 2019, 21:05

Aha i see! Thank you very much for your time and help!


@pejman101