Topics
30 Jul 2023, 08:21
 398
 2
12 Aug 2021, 13:05
 910
 2
Replies

wmclennan77
14 Sep 2023, 08:04

RE: Indicator difficulty: Index was outside the bounds of the array

PanagiotisChar said: 

Hi there,

Your problem is probably here

            //Initialize source array            if (sourceValue == null)            {                sourceValue = new double[index];            }            //Create index for source            sourceValue[index] = GetIndiSet(index);

In C# indexing starts from 0. So the max index for an array with a length of index is index - 1.

Hi,

Thanks for the response and assistance.

I updated the method as follows:

public override void Calculate(int index)
        {
            if (index < lengthParameter)
            {
                return;
            }

            //Initialize source array
            if (sourceValue == null)
            {
                sourceValue = new double[index];
            }

            //Create index for source - updated to index - 1
            sourceValue[index - 1] = GetIndiSet(index);

            GetMRC(index);
        }

I am still receiving the same error, could it be one of the other arrays in the code or did I make the wrong alteration?


@wmclennan77

wmclennan77
30 Jul 2023, 18:15 ( Updated at: 21 Dec 2023, 09:23 )

RE: Fractal Lines Indicator

firemyst said: 

One issue you'll have is the trendlines are overwriting each other because you're giving them the same names.

 

Change the line:

ObjUp = string.Format("UpTrendLine");

to be this instead:

ObjUp = string.Format("UpTrendLine") + index.toString();

 

Do the same for the down trend line. This way, every up obj and down obj will have unique names so they won't overwrite each other.

Hi, 

Thanks for the response.

I made the changes you suggested and did get the indicator to start drawing lines, but noticed that there is only one line at a random spot on the chart:

Any advice on why it's drawing incorrectly and only in one spot?


@wmclennan77

wmclennan77
07 Jun 2023, 09:00

RE:

firemyst said:

Y1 is typically the first parameter that specifies a value along the Y-axis of the chart.

However, looking at your code, I didn't see anything wrong.

I then ran it in Visual Studio and there were no crashes or faults among 5 forex pairs and the US30 charts.

So what symbol and timeframe were you running this on?

Hi, the error seems to have disappeared when I added: if (Direction == 0) return;

I don't know why, but that seems to have solved it.


@wmclennan77

wmclennan77
11 Mar 2022, 11:42

RE:

amusleh said:

Hi,

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class AFFS : Robot
    {
        [Parameter("Name", DefaultValue = "AFFS")]
        public string _name { get; set; }

        [Parameter("Start Hour", DefaultValue = 6.0)]
        public double _starttime { get; set; }

        [Parameter("Stop Hour", DefaultValue = 18.0)]
        public double _stoptime { get; set; }

        [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)]
        public double _maxlots { get; set; }

        [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _startingrisk { get; set; }

        [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _riskstep { get; set; }

        [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _takeprofit { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _stoploss { get; set; }

        [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _safety { get; set; }

        [Parameter("High/Low Timeframe", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }

        private Bars _hlbars;
        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk;
        private bool _todaybuy, _todaysell;

        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);

            _safety *= Symbol.PipSize;
        }

        protected override void OnBar()
        {
            var _currenthours = Server.Time.TimeOfDay.TotalHours;
            bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime;

            _activerisk = GetRisk();
            var _volume = GetVolume();
            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }
            _previoushigh = _hlbars.HighPrices.Last(1);
            _previouslow = _hlbars.LowPrices.Last(1);
            _bullprice = Symbol.Ask + _safety;
            _bearprice = Symbol.Bid - _safety;

            if (_tradetime && !_todaybuy)
            {
                if (_bullprice > _previoushigh)
                {
                    ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaybuy = true;
                }
            }
            if (!_tradetime && _todaybuy)
            {
                _todaybuy = false;
            }

            if (_tradetime && !_todaysell)
            {
                if (_bearprice < _previouslow)
                {
                    ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaysell = true;
                }
            }
            if (!_tradetime && _todaysell)
            {
                _todaysell = false;
            }
        }

        private double GetRisk()
        {
            double _result = 0.0;
            double _maxrisk = 10.0;
            var _lastposition = History.FindLast(_name);
            bool _win = _lastposition != null && _lastposition.NetProfit > 0.0 ? true : false;
            if (_win && _activerisk < _maxrisk)
            {
                _result = _activerisk + _riskstep;
            }
            else if (!_win)
            {
                _result = _startingrisk;
            }
            return _result;
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _activerisk / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }

            return result;
        }
    }
}

 

Hi amusleh,

I have one more issue if you can help me.

In the bot above, is there any way to check in the OnStart if:
In the _hlbars period,  the one entry for the day has already happened? If so, the bot cannot trade until the next period.

 

For example, if HL is set to daily and I start the bot at 2 PM and today's entry happened at 1 PM, I don't want the bot to trade until the next day.

What is happening now is when I initialize the bot, the logic sees that the current price is higher than the previous high, and makes a buy immediately. This is wrong since the ideal entry has passed.

Any help would be greatly appreciated, thanks.


@wmclennan77

wmclennan77
10 Mar 2022, 13:25

RE:

amusleh said:

Hi,

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class AFFS : Robot
    {
        [Parameter("Name", DefaultValue = "AFFS")]
        public string _name { get; set; }

        [Parameter("Start Hour", DefaultValue = 6.0)]
        public double _starttime { get; set; }

        [Parameter("Stop Hour", DefaultValue = 18.0)]
        public double _stoptime { get; set; }

        [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)]
        public double _maxlots { get; set; }

        [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _startingrisk { get; set; }

        [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _riskstep { get; set; }

        [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _takeprofit { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _stoploss { get; set; }

        [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _safety { get; set; }

        [Parameter("High/Low Timeframe", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }

        private Bars _hlbars;
        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk;
        private bool _todaybuy, _todaysell;

        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);

            _safety *= Symbol.PipSize;
        }

        protected override void OnBar()
        {
            var _currenthours = Server.Time.TimeOfDay.TotalHours;
            bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime;

            _activerisk = GetRisk();
            var _volume = GetVolume();
            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }
            _previoushigh = _hlbars.HighPrices.Last(1);
            _previouslow = _hlbars.LowPrices.Last(1);
            _bullprice = Symbol.Ask + _safety;
            _bearprice = Symbol.Bid - _safety;

            if (_tradetime && !_todaybuy)
            {
                if (_bullprice > _previoushigh)
                {
                    ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaybuy = true;
                }
            }
            if (!_tradetime && _todaybuy)
            {
                _todaybuy = false;
            }

            if (_tradetime && !_todaysell)
            {
                if (_bearprice < _previouslow)
                {
                    ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaysell = true;
                }
            }
            if (!_tradetime && _todaysell)
            {
                _todaysell = false;
            }
        }

        private double GetRisk()
        {
            double _result = 0.0;
            double _maxrisk = 10.0;
            var _lastposition = History.FindLast(_name);
            bool _win = _lastposition != null && _lastposition.NetProfit > 0.0 ? true : false;
            if (_win && _activerisk < _maxrisk)
            {
                _result = _activerisk + _riskstep;
            }
            else if (!_win)
            {
                _result = _startingrisk;
            }
            return _result;
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _activerisk / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }

            return result;
        }
    }
}

 

Hi amusleh,

Thanks, works perfectly!


@wmclennan77

wmclennan77
29 Jul 2021, 13:27

RE:

amusleh said:

Hi,

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class RiskonSL : Robot
    {
        [Parameter("Label", DefaultValue = "")]
        public string _Label { get; set; }

        [Parameter("Risk %", DefaultValue = 1.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.1)]
        public double _RiskPercent { get; set; }

        [Parameter("Max Allowed Lots", DefaultValue = 10.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _MaxLots { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _SL { get; set; }

        [Parameter("Take Profit", DefaultValue = 15.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _TP { get; set; }

        private ExponentialMovingAverage _ema_12;
        private ExponentialMovingAverage _ema_26;
        private bool _ema_buy, _ema_sell;

        protected override void OnStart()
        {
            _ema_12 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 12);
            _ema_26 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 26);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(_Label, SymbolName, TradeType.Sell);

            var volume = GetVolume();

            if (_ema_12.Result.HasCrossedAbove(_ema_26.Result.Last(1), 1))
            {
                _ema_buy = true;
                _ema_sell = false;
            }
            else if (_ema_12.Result.HasCrossedBelow(_ema_26.Result.Last(1), 1))
            {
                _ema_sell = true;
                _ema_buy = false;
            }

            if (ActiveBuy == null && _ema_buy)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, _Label, _SL, _TP);
            }

            if (ActiveSell == null && _ema_sell)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, _Label, _SL, _SL);
            }
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Equity;

            double sizeInLots = Math.Round((baseNumber * _RiskPercent / 100) / (_SL * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }

            return result;
        }
    }
}

 

Hi, 

Works perfect, thanks!


@wmclennan77

wmclennan77
29 Jul 2021, 10:44

RE:

amusleh said:

Hi,

Please post a full cBot sample that uses your calculation code and then we will be able to help you.

Hi,

Here is an example of the calculation code implemented in an example basic MA cross strategy.

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class RiskonSL : Robot
    {
        private double _volume;
        private double _AdjRisk;
        private double _AdjStop;
        private double _MaxUnits;

        [Parameter("Label", DefaultValue = "")]
        public string _Label { get; set; }

        [Parameter("Risk %", DefaultValue = 1.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.1)]
        public double _RiskPercent { get; set; }

        [Parameter("Max Allowed Lots", DefaultValue = 10.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _MaxLots { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _SL { get; set; }

        [Parameter("Take Profit", DefaultValue = 15.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _TP { get; set; }

        private ExponentialMovingAverage _ema_12;
        private ExponentialMovingAverage _ema_26;
        private bool _ema_buy, _ema_sell;

        protected override void OnStart()
        {
            _ema_12 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 12);
            _ema_26 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 26);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(_Label, SymbolName, TradeType.Sell);

            _MaxUnits = Symbol.QuantityToVolumeInUnits(_MaxLots);
            _AdjRisk = _RiskPercent / 100;
            _AdjStop = _SL / Symbol.PipValue;
            _volume = (long)Math.Ceiling((Account.Balance * _AdjRisk) / _AdjStop) * 1000;
            if (_volume > _MaxUnits)
            {
                _volume = _MaxUnits;
            }

            if (_ema_12.Result.HasCrossedAbove(_ema_26.Result.Last(1), 1))
            {
                _ema_buy = true;
                _ema_sell = false;
            }
            else if (_ema_12.Result.HasCrossedBelow(_ema_26.Result.Last(1), 1))
            {
                _ema_sell = true;
                _ema_buy = false;
            }

            if (ActiveBuy == null && _ema_buy)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volume, _Label, _SL, _TP);
            }

            if (ActiveSell == null && _ema_sell)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volume, _Label, _SL, _SL);
            }
        }
    }
}

 


@wmclennan77

wmclennan77
14 Jul 2021, 10:22

RE:

akbarlotfi15168 said:

Hello

You should first write the indicator then call it in your robot with

Your IndicatorNameInRobot = Indicators.GetIndicator<YourIndicatorName>(YourIndicatorFirstParameter,YourIndicatorSecondParameter);

Then Below the Ontick()

double YourIndicatorFirstNeededOutput = IndicatorNameInRobot.YourIndicatorOutputName.Last();

Your mistake is you use getindicator in your indicator with the it's namespace in itself.

Hi there,

Thank you for your help so far, if you don't mind there is still an issue.

When calling in the bot as you said, I get an error described as "Error CS0246: The type or namespace name 'SampleVWAP' could not be found (are you missing a using directive or an assembly reference?)"

I have added the reference to the indicator in the bot via Manage References.


@wmclennan77

wmclennan77
08 Jul 2021, 10:00

RE:

PanagiotisCharalampous said:

Hi wmclennan77,

For the most part, the filter works as intended.

Can you clearly explain the intention?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook 

Hi Panagiotis,

So the intention of this indicator is to dictate in which direction positions are allowed to open.

If the price is higher than the high EMA, then buys are allowed, sells are not.

The opposite is true with selling, where if the price is lower than the low EMA, then sells are allowed and buys are not.

 

As mentioned, the buying and selling bias works fine.

 

An example: if the price was above the high EMA, a buy would be opened. If the price dips down to below the high EMA, it needs to close that buy and either wait for the price to go above high EMA again for a buy or go below low EMA for a sell. There are no trades allowed between high and low EMAs.

 

The problem is positions stay open when crossing their respective EMA. Like the example buy will stay open and only close on the cross of the low EMA.


@wmclennan77

wmclennan77
07 Jul 2021, 21:37

RE:

PanagiotisCharalampous said:

Hi wmclennan77,

Well the condition seems correct to me.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

On building, there is an error described as:

"Error CS1061: 'cAlgo.API.Bars' does not contain a definition for 'Close' and no extension method 'Close' accepting a first argument of type 'cAlgo.API.Bars' could be found (are you missing a using directive or an assembly reference?)"

Am I using the wrong interface/property?


@wmclennan77

wmclennan77
07 Jul 2021, 09:23

RE:

PanagiotisCharalampous said:

Hi wmclennan77,

I am not sure what is the question here. What advice do you need?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

Essentially there are two confirmations required for entry. 

The first one is not mentioned here, as it's not relevant to my question. The only important thing to note about this first confirmation is that it will give me the direction of the first bar in the comparison.

After this, the second bar needs to be compared to the first on the closure of the second. If the direction matches (eg. the first bar is a buy, the second is also a buy), it's good to enter.

Basically, I need to tell if the second bar is a buy or sell relative to the first one.


@wmclennan77

wmclennan77
02 Jul 2021, 12:38

RE:

amusleh said:

Hi,

Your cBot code had few bugs that were causing it to crash, I fixed it but there is still no trade because your entry logic is very strict:

using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace FirstBot
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class cAlgo : Robot
    {
        private double _volumeInUnits;

        [Parameter("Label", DefaultValue = "Sample")]
        public string Label { get; set; }

        [Parameter("Volume (Lots)", DefaultValue = 0.01)]
        public double VolumeInLots { get; set; }

        [Parameter(DefaultValue = 100, MinValue = 1)]
        public int StopLoss { get; set; }

        [Parameter(DefaultValue = 150, MinValue = 1)]
        public int TakeProfit { get; set; }

        [Parameter("MACD LongCycle", DefaultValue = 26, MinValue = 1)]
        public int LongCycle { get; set; }

        [Parameter("MACD ShortCycle", DefaultValue = 12, MinValue = 1)]
        public int ShortCycle { get; set; }

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

        [Parameter("MA Type", DefaultValue = 6)]
        public MovingAverageType MaType { get; set; }

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

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

        [Parameter("K Slowing", DefaultValue = 3)]
        public int K_Slowing { get; set; }

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

        [Parameter("MA Bias", DefaultValue = 50)]
        public int MA_Bias { get; set; }

        public static TimeFrame Minute15;

        private MacdCrossOver _MACD;
        private StochasticOscillator _SOC;
        private ExponentialMovingAverage _MA_50;
        private bool MACDBuy;
        private bool MACDSell;
        private bool SOCBuy;
        private bool SOCSell;
        private bool MA_BiasBuy;
        private bool MA_BiasSell;

        protected override void OnStart()
        {
            _volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
            MACDBuy = false;
            MACDSell = false;
            SOCBuy = false;
            SOCSell = false;
            MA_BiasBuy = false;
            MA_BiasSell = false;
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, MACDPeriod);
            _SOC = Indicators.StochasticOscillator(KPeriods, K_Slowing, DPeriods, MaType);
            _MA_50 = Indicators.ExponentialMovingAverage(Price, MA_Bias);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(Label, SymbolName, TradeType.Sell);

            // MACD cross
            if (_MACD.MACD.Last(1) < _MACD.Signal.Last(1) && _MACD.MACD.Last(0) > _MACD.Signal.Last(0) && _MACD.Signal.Last(0) < 0)
            {
                MACDBuy = true;
            }
            else if (_MACD.MACD.Last(1) > _MACD.Signal.Last(1) && _MACD.MACD.Last(0) < _MACD.Signal.Last(0) && _MACD.Signal.Last(0) > 0)
            {
                MACDSell = true;
            }

            // Stochastic cross
            if (_SOC.PercentK.HasCrossedAbove(_SOC.PercentD, 0) && _SOC.PercentK.Last(1) <= 20)
            {
                if (_SOC.PercentK.Last(1) > 80)
                {
                    SOCBuy = true;
                }
            }
            else if (_SOC.PercentK.HasCrossedBelow(_SOC.PercentD, 0) && _SOC.PercentK.Last(1) >= 80)
            {
                if (_SOC.PercentK.Last(1) < 20)
                {
                    SOCSell = true;
                }
            }
            // Moving Average Bias

            if (Symbol.Bid > _MA_50.Result.LastValue)
            {
                MA_BiasBuy = true;
            }
            else if (Symbol.Bid > _MA_50.Result.LastValue)
            {
                MA_BiasSell = true;
            }

            if (MACDBuy == true && SOCBuy == true && MA_BiasBuy == true && ActiveBuy == null)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }

                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
            }

            if (MACDSell == true && SOCSell == true && MA_BiasSell == true && ActiveSell == null)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }

                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
            }
        }
    }
}

If you remove some of the entry conditions you will see trades on back test, also please don't user the Last(0) or LastValue on your cBot, it gives you the latest not closed value of a data series, which can be non deterministic, instead use Last(1) and Last(2).

If you couldn't figure out how to develop the cBot based on your requirements you can post a job request or ask one of our consultants to do it for you.

Hi amusleh,

Thanks a lot for your assistance regarding code bugs. I'm new to C# as I have transitioned from Obj Pascal, but I enjoy trading and learning.

I have realised that there are definitely some logic errors as this strategy is one I've traded manually and definitely works. It's not the most profitable, but easy enough to learn on.

 

The core idea is that on every candle close, provided that there is no trade open already, if the MACD is crossed up, the Stochastic is crossed up and below the stated level, and the position of price in relation to the EMA is the same, then a position will open.

On backtest it seems like the stochastic is what's causing the problems, as I've removed and individually tested each component. Also, the bot seems to have trouble opening short positions at all, which leads to a terrible equity graph.

 

Is the strategy accurately reflected in the code? Any input would be great appreciated.


@wmclennan77

wmclennan77
30 Jun 2021, 22:14

RE:

PanagiotisCharalampous said:

Hi wmclennan77,

It would look like this

           if(stochastic.PercentK.Last(1) > 80)
           {
            // do something
           }

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

If you don't mind, would you take a look at my code?

When running a backtest, the robot creates no positions at all.

It is my first robot, so I'm unsure.

 

using System;
using System.Linq;
using cAlgo.API;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace FirstBot
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]

    public class cAlgo : Robot
    {
        private double _volumeInUnits;

        [Parameter("Label", DefaultValue = "Sample")]
        public string Label { get; set; }

        [Parameter("Volume (Lots)", DefaultValue = 0.01)]
        public double VolumeInLots { get; set; }

        [Parameter(DefaultValue = 100, MinValue = 1)]
        public int StopLoss { get; set; }

        [Parameter(DefaultValue = 150, MinValue = 1)]
        public int TakeProfit { get; set; }

        [Parameter("MACD LongCycle", DefaultValue = 26, MinValue = 1)]
        public int LongCycle { get; set; }

        [Parameter("MACD ShortCycle", DefaultValue = 12, MinValue = 1)]
        public int ShortCycle { get; set; }

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

        [Parameter("MA Type", DefaultValue = 6)]
        public MovingAverageType MaType { get; set; }

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

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

        [Parameter("K Slowing", DefaultValue = 3)]
        public int K_Slowing { get; set; }

        public DataSeries Price { get; set; }

        [Parameter("MA Bias", DefaultValue = 50)]
        public int MA_Bias { get; set; }

        public static TimeFrame Minute15;

        private MacdCrossOver _MACD;
        private StochasticOscillator _SOC;
        private ExponentialMovingAverage _MA_50;
        bool MACDBuy;
        bool MACDSell;
        bool SOCBuy;
        bool SOCSell;
        bool MA_BiasBuy;
        bool MA_BiasSell;

        protected override void OnStart()
        {
            _volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
            MACDBuy = false;
            MACDSell = false;
            SOCBuy = false;
            SOCSell = false;
            MA_BiasBuy = false;
            MA_BiasSell = false;
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, MACDPeriod);
            _SOC = Indicators.StochasticOscillator(KPeriods, K_Slowing, DPeriods, MaType);
            _MA_50 = Indicators.ExponentialMovingAverage(Price, MA_Bias);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(Label, SymbolName, TradeType.Sell);

            // MACD cross
            if (_MACD.MACD.Last(1) < _MACD.Signal.Last(1) && _MACD.MACD.Last(0) > _MACD.Signal.Last(0) && _MACD.Signal.Last(0) < 0)
            {
                MACDBuy = true;
            }

            else if (_MACD.MACD.Last(1) > _MACD.Signal.Last(1) && _MACD.MACD.Last(0) < _MACD.Signal.Last(0) && _MACD.Signal.Last(0) > 0)
            {
                MACDSell = true;

            }

            // Stochastic cross
            if (_SOC.PercentK.HasCrossedAbove(_SOC.PercentD, 0) && _SOC.PercentK.Last(1) <= 20)
            {
                if (_SOC.PercentK.Last(1) > 80)
                {
                    SOCBuy = true;
                }

            }

            else if (_SOC.PercentK.HasCrossedBelow(_SOC.PercentD, 0) && _SOC.PercentK.Last(1) >= 80)
            {
                if (_SOC.PercentK.Last(1) < 20)
                {
                    SOCSell = true;
                }
            }

            // Moving Average Bias
            if (Symbol.Bid > _MA_50.Result.LastValue)
            {
                MA_BiasBuy = true;
            }

            else if (Symbol.Bid > _MA_50.Result.LastValue)
            {
                MA_BiasSell = true;
            }

            if (MACDBuy == true && SOCBuy == true && MA_BiasBuy == true && ActiveBuy == null)
            {
                ClosePosition(ActiveSell);
                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
            }

            if (MACDSell == true && SOCSell == true && MA_BiasSell == true && ActiveSell == null)
            {
                ClosePosition(ActiveBuy);
                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLoss, TakeProfit);
            }


        }

    }

}


@wmclennan77