Topics
20 Oct 2022, 17:50
 780
 2
23 Sep 2022, 08:51
 703
 2
04 Jul 2022, 14:01
 840
 6
05 Feb 2022, 07:10
 958
 4
14 Sep 2021, 11:31
 1440
 5
Replies

waym77
02 Nov 2022, 14:21

RE: RE:

Waxy said:

 

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

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private ChartVerticalLine _verticalLine;

        /*
         -- I was wondering if it were possible for me to get the Bars info (eg. OpenPrices, ClosePrices, etc.) from a ChartObject's (such as a vertical line) Time index?           
         -- Any help is appreciated, thanks.
         */

        protected override void Initialize()
        {
            _verticalLine = Chart.DrawVerticalLine("VerticalLine", Bars.OpenTimes.LastValue, Color.Red);

            var index = Bars.OpenTimes.GetIndexByTime(_verticalLine.Time);

            var bar = Bars[index];
            
            Print("Open: {0}, High: {1}, Low: {2}, Close: {3}", bar.Open, bar.High, bar.Low, bar.Close);
        }

        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = 
        }
    }
}

 

Hi, thanks for this!

I was also wondering if there is any way to check at which bar index the price crosses a certain number?

Thanks,


@waym77

waym77
23 Sep 2022, 08:48

Real-world market conditions are always different from backtests. I once created a bot based on the stochastic oscillator with a similar style of TP (1-5 pips) that gave me a 150,000% increase over a 10-year backtest. It then proceeded to lose money instantly. 

In reality, you should only backtest a bot to see if it works as intended (creating positions when conditions are met). I would suggest forward testing via demo as a more viable way to test this, as most brokers' demo accounts simulate current liquidity scenarios.


@waym77

waym77
14 Jul 2022, 09:04

RE:

PanagiotisCharalampous said:

Hi waym77,

No, cTrader does not support FOK orders at the moment.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi,

Thanks for the response. Are FoK orders on Spotware's timeline at the moment?


@waym77

waym77
06 Jul 2022, 08:56

RE:

PanagiotisCharalampous said:

Hi waym77,

You can't use Bars.OpenTimes because it does not contain the time you want. You need to set the actual time you need.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi, 

Thanks, would you mind providing me with an example related to the DrawText? Wouldn't the time specified be needed to be adjusted for each timeframe?

I'm unfamiliar with DateTime, as I've only ever used Bars.OpenTimes for Chart Objects until now.


@waym77

waym77
05 Jul 2022, 14:25

RE:

PanagiotisCharalampous said:

Hi waym77,

There is nothing special about this. You just need to use the starting and ending time you need.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis, 

 

Thanks for the reply.

 

That I do understand, regarding X being related to OpenTimes.Last. My confusion is more in the sense of how to draw ahead of LastValue?

For instance:

Chart.DrawText("Object", "Sample", Bars.OpenTimes.Last(?), Bars.HighPrices.LastValue, Color.White);

The (?) is where my confusion is.

 

Thanks,


@waym77

waym77
14 Apr 2022, 11:52

RE:

amusleh said:

Hi,

Right now the session data is not available on Automate API, you can code it by using some fixed hours of day for each session.

We might consider adding this data in future version of cTrader Automate.

Thanks, I'll add it manually.

What are the fixed hours according to cTrader?


@waym77

waym77
11 Apr 2022, 07:25

RE:

amusleh said:

Hi,

You can separate each instance orders by using the Symbol name, example:

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

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

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

        [Parameter("Take Profit", Group = "Risk", DefaultValue = 15.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _takeprofit { get; set; }

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

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

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

        private Bars _hlbars;
        private double _previoushigh, _previouslow, _volume;
        private bool _todaybuyhappened, _todaysellhappened;

        public IEnumerable<PendingOrder> BotPendingOrders
        {
            get
            {
                return PendingOrders.Where(order => order.SymbolName.Equals(SymbolName, StringComparison.Ordinal) && order.Label.Equals(_name, StringComparison.Ordinal));
            }
        }

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

            _hlbars.BarOpened += _hlbars_BarOpened;
            _safety *= Symbol.PipSize;

            Positions.Closed += PositionsOnClosed;

            _todaybuyhappened = true;
            _todaysellhappened = true;
        }

        private void _hlbars_BarOpened(BarOpenedEventArgs obj)
        {
            _todaybuyhappened = false;
            _todaysellhappened = false;

            foreach (var _PendingOrders in BotPendingOrders)
            {
                CancelPendingOrder(_PendingOrders);
            }

            if (_hlbars.OpenPrices.Last(0) > _hlbars.HighPrices.Last(1))
            {
                _todaybuyhappened = true;
            }

            if (_hlbars.OpenPrices.Last(0) < _hlbars.LowPrices.Last(1))
            {
                _todaysellhappened = true;
            }

            _volume = GetVolume();

            _previoushigh = Math.Abs(_hlbars.HighPrices.Last(1) + _safety);
            _previouslow = Math.Abs(_hlbars.LowPrices.Last(1) - _safety);

            if (!_todaybuyhappened)
            {
                PlaceStopOrder(TradeType.Buy, Symbol.Name, _volume, _previoushigh, _name, _stoploss, _takeprofit);
                _todaybuyhappened = true;
            }

            if (!_todaysellhappened)
            {
                PlaceStopOrder(TradeType.Sell, Symbol.Name, _volume, _previouslow, _name, _stoploss, _takeprofit);
                _todaysellhappened = true;
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            _volume = GetVolume();

            foreach (var _PendingOrders in BotPendingOrders)
            {
                if (_PendingOrders.VolumeInUnits != _volume)
                {
                    _PendingOrders.ModifyVolume(_volume);
                }
            }
        }

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

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _riskpercent / 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;
        }
    }
}

The BotPendingOrders enumerable will give you only those orders that are from same symbol and with same Label.

Hi, this works perfectly, thanks! 


@waym77

waym77
07 Apr 2022, 16:10

RE:

amusleh said:

Hi,

Check the API references for a sample: Event Closed | API reference | cTrader Community

Thanks for the inclusion of the API reference.

The updated code looks to be running correctly, thanks.


@waym77

waym77
07 Apr 2022, 07:58

RE:

amusleh said:

Hi,

The account balance is updated when you close a position, or you deposit/withdraw funds, for later two there is no way to know that but for position close you can use the Positions Closed event.

So what you need to do is first subscribe to Positions.Closed event and then move your calculation logic to Positions closed event handler.

Hi,

Thanks for your response. I am, however, unfamiliar with Positions.Closed events. Do you maybe have a code sample so I can see where and how to place the calculation logic?


@waym77

waym77
15 Mar 2022, 09:29

RE:

amusleh said:

Hi,

This can be caused by symbol spread or something might be wrong with your code, can you post a sample cBot code that can reproduce this issue on visual back test?

Here is the current build used:

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.SouthAfricaStandardTime, AccessRights = AccessRights.FullAccess)]
    public class AFFS : Robot
    {
        [Parameter("Name", Group = "Info", DefaultValue = "AFFS")]
        public string _name { get; set; }

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

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

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

        [Parameter("Max Risk (%)", Group = "Risk", DefaultValue = 20.0, MinValue = 0.01, MaxValue = 100.0, Step = 0.5)]
        public double _maxrisk { get; set; }

        [Parameter("Stop Loss", Group = "Risk", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 1000.0, Step = 1.0)]
        public double _stoploss { get; set; }

        [Parameter("Reward Factor", Group = "Risk", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 50.0, Step = 0.5)]
        public double _reward { get; set; }

        [Parameter("Safety (Pips)", Group = "Risk", DefaultValue = 3.0, MinValue = 0.0, MaxValue = 1000.0, Step = 1.0)]
        public double _safety { get; set; }

        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk, _distance, _volume, _takeprofit;
        private bool _todaybuy, _todaysell, _intimeforbuy, _intimeforsell, _gapbuy, _gapsell;
        private int _buycount, _sellcount, _tradedaybuy, _tradedaysell;

        protected override void OnStart()
        {
            _buycount = 1;
            _sellcount = 1;

            _distance = Math.Abs(_safety * Symbol.PipSize);
            _activerisk = _startingrisk;
            _volume = GetVolume();
            _takeprofit = GetRR();

            _previoushigh = Bars.HighPrices.Last(1);
            _previouslow = Bars.LowPrices.Last(1);
            _bullprice = _previoushigh + _distance;
            _bearprice = _previouslow - _distance;

            if (Bars.LowPrices.Last(0) < _bearprice)
            {
                _intimeforsell = false;
            }

            if (Bars.HighPrices.Last(0) > _bullprice)
            {
                _intimeforbuy = false;
            }
        }

        protected override void OnTick()
        {
            if (Server.Time.Day > _tradedaybuy)
            {
                _buycount = 1;
                _intimeforbuy = true;
                _gapbuy = false;
            }

            if (Server.Time.Day > _tradedaysell)
            {
                _sellcount = 1;
                _intimeforsell = true;
                _gapsell = false;
            }

            _gapbuy = Bars.OpenPrices.Last(0) > _previoushigh;
            _gapsell = Bars.OpenPrices.Last(0) < _previouslow;

            if (_gapbuy && Symbol.Ask < _previoushigh)
            {
                _gapbuy = false;
            }

            if (_gapsell && Symbol.Bid > _previouslow)
            {
                _gapsell = false;
            }

            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }

            _todaybuy = _buycount == 1;
            _todaysell = _sellcount == 1;

            _previoushigh = Bars.HighPrices.Last(1);
            _previouslow = Bars.LowPrices.Last(1);
            _bullprice = _previoushigh + _distance;
            _bearprice = _previouslow - _distance;

            if (Symbol.Ask > _bullprice && _todaybuy && _intimeforbuy && !_gapbuy)
            {
                _tradedaybuy = Server.Time.Day;
                _activerisk = GetRisk();
                _volume = GetVolume();
                ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                _buycount = 0;
            }

            if (Symbol.Bid < _bearprice && _todaysell && _intimeforsell && !_gapsell)
            {
                _tradedaysell = Server.Time.Day;
                _activerisk = GetRisk();
                _volume = GetVolume();
                ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                _sellcount = 0;
            }

        }

        private double GetRR()
        {
            double _result = 0.0;
            _result = Math.Abs(_stoploss * _reward);
            return _result;
        }

        private double GetRisk()
        {
            double _result = _activerisk;
            if (_result > _maxrisk)
            {
                _result = _maxrisk;
            }
            if (History.FindLast(_name) != null)
            {
                var _lastposition = History.FindLast(_name);
                bool _win = _lastposition.NetProfit > 0.0;
                if (_win && _activerisk < _maxrisk)
                {
                    _result = _activerisk + _riskstep;
                }
                else if (!_win)
                {
                    _result = _startingrisk;
                }
            }
            else
                return _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;
        }
    }
}

 


@waym77

waym77
08 Feb 2022, 19:46 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

Hi,

Please 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 MACDBot : Robot

    {
        [Parameter("Name", Group = "General", DefaultValue = "MACD Bot")]
        public string _Label { get; set; }

        [Parameter("MACD Long", Group = "MACD", DefaultValue = 26, MaxValue = 100, MinValue = 1)]
        public int _macdlong { get; set; }

        [Parameter("MACD Short", Group = "MACD", DefaultValue = 12, MaxValue = 100, MinValue = 1)]
        public int _macdshort { get; set; }

        [Parameter("MACD Signal", Group = "MACD", DefaultValue = 9, MaxValue = 100, MinValue = 1)]
        public int _macdsig { get; set; }

        [Parameter("MA Type", Group = "Moving Average", DefaultValue = MovingAverageType.Exponential)]
        public MovingAverageType _matype { get; set; }

        [Parameter("MA Period", Group = "Moving Average", DefaultValue = 200, MaxValue = 1000, MinValue = 1)]
        public int _maperiod { get; set; }

        [Parameter("Reward", Group = "Risk", DefaultValue = 1.5, MaxValue = 10.0, MinValue = 0.1, Step = 0.1)]
        public double _reward { get; set; }

        [Parameter("Pip Limiter", Group = "Risk", DefaultValue = 8.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _limiter { get; set; }

        [Parameter("Position Size", Group = "Risk", DefaultValue = 1.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _size { get; set; }

        [Parameter("Stop Loss Buffer", Group = "Risk", DefaultValue = 1.0, MaxValue = 50.0, MinValue = 0.01, Step = 0.01)]
        public double _slbuffer { get; set; }

        public MacdCrossOver _macd;
        public MovingAverage _ma;
        private bool _macdbuy, _macdsell, _maq, _distanceq;
        public double _getsl, _gettp, _distance;

        protected override void OnStart()
        {
            _macd = Indicators.MacdCrossOver(_macdlong, _macdshort, _macdsig);
            _ma = Indicators.MovingAverage(Bars.ClosePrices, _maperiod, _matype);
            _slbuffer = 1.0;
            _distance = 0.0;
        }

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

            var _volume = Symbol.QuantityToVolumeInUnits(_size);
            _distance = Math.Abs((_ma.Result.LastValue - Bars.ClosePrices.LastValue) / Symbol.PipSize);

            _maq = Bars.ClosePrices.Last(1) > _ma.Result.Last(1) ? true : false;
            _distanceq = _distance < _limiter ? true : false;

            if (_macd.MACD.HasCrossedAbove(_macd.Signal, 1) && _macd.MACD.Last(1) < 0)
            {
                _macdbuy = true;
            }

            if (_macd.MACD.HasCrossedBelow(_macd.Signal, 1) && _macd.MACD.Last(1) > 0)
            {
                _macdsell = true;
            }

            if (_activebuy == null && _maq && _distanceq && _macdbuy)
            {
                _getsl = GetStopLoss();
                _gettp = GetTakeProfit();

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

                ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _Label, _getsl, _gettp);
            }

            if (_activesell == null && !_maq && _distanceq && _macdsell)
            {
                _getsl = GetStopLoss();
                _gettp = GetTakeProfit();

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

                ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _Label, _getsl, _gettp);
            }
        }

        private double GetStopLoss()
        {
            double _result = Math.Abs((_ma.Result.Last(1) - Bars.ClosePrices.Last(1)) / Symbol.PipSize);
            _result = _result + _slbuffer;
            return _result;
        }

        private double GetTakeProfit()
        {
            double result = _getsl * _reward;
            return result;
        }
    }
}

I back tested it and it works fine:

Hi Amusleh,

 

Thanks so much for your help so far.

However, I'm still having problems with the same thing.

Please see my example below:

The purple line is where the entry is supposed to be. I'm not sure how to fix this.

Thanks in advance,


@waym77

waym77
22 Sep 2021, 09:56

RE: RE: RE: RE:

firemyst said:

Have you tried passing in the MA objects in the "constructor" to your TradingPanel inner class?

You'll have to create the Constructor with the appropriate parameters.

 

Hi there, forgive me, I am not very familiar with constructor arguments.

Would it look something like below?

public TradingPanel(MovingAverage TrendMA, Robot robot, Symbol symbol, double defaultPrice, double defaultFrag, double defaultLots, double defaultRisk, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            TrendMA = Indicators.MovingAverage(Bars.ClosePrices, TrendPeriods, MovingAverageType.Exponential);
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultPrice, defaultFrag, defaultLots, defaultRisk, defaultStopLossPips, defaultTakeProfitPips));
        }

I understand I'll also have to create new parameters for values like TrendPeriods in this class.

Thanks,


@waym77

waym77
21 Sep 2021, 10:37

RE: RE:

firemyst said:

waym77 said:

Hi all, 

 

I'm having trouble using an indicator in a separate class from the Robot (Main) class.

 

In the Robot class, I have the parameters and declarations for using an EMA, but since that class is separate from the other public class in which I wish to use the EMA Result, I get an error saying ''Error CS0103: The name 'TrendMA' does not exist in the current context". 

 

I understand that this is because the EMA is local to the Main Robot class, though I'm having trouble calling the indicator into the class where I want to use it. 

 

The short of my question is then: how can I call and declare an indicator in a class that is not the Main Robot class?

Please excuse my lack of code sample, the source for this bot is long, although I can provide it on request.

 

Thanks,

In short, without seeing any sample code posted of yours:

1) you need to "reference" the class. In the cTrader Automate section when you view your bot's source code, click on the triple-dot menu to manage references and make sure it's included

2) reference your TrendMA indicator similar to the following:

TrendMA _ma = Indicators.GetIndicator<TrendMA>(the list of parameters required);

 

Hi firemyst,

 

Thanks for the response, I appreciate it.

Your suggestion makes sense, referencing the indicator to the class, although I'm having trouble with the actual location.

I've attached the source code to show what I mean:

The main class (EZSUltimate) contains the parameters and the OnStart method which is where indicators normally go.

I would like to use those three EMAs in the TradingPanel class, specifically in the Calc_SL() method.

Thanks for your help.

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EZSUltimate : Robot
    {
        [Parameter("Vertical Position", Group = "Panel alignment", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment PanelVerticalAlignment { get; set; }

        [Parameter("Horizontal Position", Group = "Panel alignment", DefaultValue = HorizontalAlignment.Left)]
        public HorizontalAlignment PanelHorizontalAlignment { get; set; }

        [Parameter("Default Price", Group = "Default trade parameters", DefaultValue = 1.0)]
        public double DefaultPrice { get; set; }

        [Parameter("Default Lots", Group = "Default trade parameters", DefaultValue = 0.01)]
        public double DefaultLots { get; set; }

        [Parameter("Default Risk", Group = "Default trade parameters", DefaultValue = 1.0)]
        public double DefaultRisk { get; set; }

        [Parameter("Default Fragmentation", Group = "Default trade parameters", DefaultValue = 1)]
        public double DefaultFrag { get; set; }

        [Parameter("Default Take Profit (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultTakeProfitPips { get; set; }

        [Parameter("Default Stop Loss (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultStopLossPips { get; set; }

        [Parameter("Moving Average Type", Group = "MA", DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MAType { get; set; }

        [Parameter("Fast MA Periods", Group = "MA", DefaultValue = 21, MinValue = 1, MaxValue = 500)]
        public int FastMAPeriods { get; set; }

        [Parameter("Slow MA Periods", Group = "MA", DefaultValue = 50, MinValue = 1, MaxValue = 1000)]
        public int SlowMAPeriods { get; set; }

        [Parameter("Trend MA Periods", Group = "MA", DefaultValue = 200, MinValue = 1, MaxValue = 1500)]
        public int TrendMAPeriods { get; set; }

        MovingAverage FastMA;
        MovingAverage SlowMA;
        MovingAverage TrendMA;

        protected override void OnStart()
        {

            var tradingPanel = new TradingPanel(this, Symbol, DefaultPrice, DefaultFrag, DefaultLots, DefaultRisk, DefaultStopLossPips, DefaultTakeProfitPips);
            FastMA = Indicators.MovingAverage(Bars.ClosePrices, FastMAPeriods, MAType);
            SlowMA = Indicators.MovingAverage(Bars.ClosePrices, SlowMAPeriods, MAType);
            TrendMA = Indicators.MovingAverage(Bars.ClosePrices, TrendMAPeriods, MAType);

            var border = new Border 
            {
                VerticalAlignment = PanelVerticalAlignment,
                HorizontalAlignment = PanelHorizontalAlignment,
                Style = Styles.CreatePanelBackgroundStyle(),
                Margin = "20 40 20 20",
                Width = 225,
                Child = tradingPanel
            };

            Chart.AddControl(border);
        }
    }

    public class TradingPanel : CustomControl
    {
        private const string RiskInputKey = "RiskKey";
        private const string LotsInputKey = "LotsKey";
        private const string SuggestedInputKey = "SuggestedKey";
        private const string PriceInputKey = "PriceKey";
        private const string FragInputKey = "FragKey";
        private const string TakeProfitInputKey = "TPKey";
        private const string StopLossInputKey = "SLKey";
        private readonly IDictionary<string, TextBox> _inputMap = new Dictionary<string, TextBox>();
        private readonly Robot _robot;
        private readonly Symbol _symbol;

        public TradingPanel(Robot robot, Symbol symbol, double defaultPrice, double defaultFrag, double defaultLots, double defaultRisk, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultPrice, defaultFrag, defaultLots, defaultRisk, defaultStopLossPips, defaultTakeProfitPips));
        }

        private ControlBase CreateTradingPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultRisk, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var mainPanel = new StackPanel();

            var header = CreateHeader();
            mainPanel.AddChild(header);

            var contentPanel = CreateContentPanel(defaultPrice, defaultFrag, defaultLots, defaultRisk, defaultStopLossPips, defaultTakeProfitPips);
            mainPanel.AddChild(contentPanel);

            return mainPanel;
        }

        private ControlBase CreateHeader()
        {
            var headerBorder = new Border 
            {
                BorderThickness = "0 0 0 1",
                Style = Styles.CreateCommonBorderStyle()
            };

            var header = new TextBlock 
            {
                Text = "Quick Trading Panel",
                Margin = "10 7",
                Style = Styles.CreateHeaderStyle()
            };

            headerBorder.Child = header;
            return headerBorder;
        }

        private StackPanel CreateContentPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultRisk, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var contentPanel = new StackPanel 
            {
                Margin = 9
            };
            var grid = new Grid(9, 3);
            grid.Columns[1].SetWidthInPixels(5);

            var sellmarketButton = CreateMarketTradeButton("MARKET SELL", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellmarketButton, 0, 0);

            var buymarketButton = CreateMarketTradeButton("MARKET BUY", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buymarketButton, 0, 2);

            var sellstopButton = CreateStopTradeButton("SELL STOP", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellstopButton, 1, 0);

            var buystopButton = CreateStopTradeButton("BUY STOP", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buystopButton, 1, 2);

            var selllimitButton = CreateLimitTradeButton("SELL LIMIT", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(selllimitButton, 3, 0);

            var buylimitButton = CreateLimitTradeButton("BUY LIMIT", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buylimitButton, 3, 2);

            var priceInput = CreateInputWithLabel("Pending Price", defaultPrice.ToString("F2"), PriceInputKey);
            grid.AddChild(priceInput, 4, 0);

            var fragInput = CreateInputWithLabel("Fragmentation", defaultFrag.ToString("F2"), FragInputKey);
            grid.AddChild(fragInput, 4, 2);

            var riskInput = CreateInputWithLabel("Risk %", defaultRisk.ToString("F2"), RiskInputKey);
            grid.AddChild(riskInput, 5, 0, 1, 3);

            var takeProfitInput = CreateInputWithLabel("Take Profit (Pips)", defaultTakeProfitPips.ToString("F1"), TakeProfitInputKey);
            grid.AddChild(takeProfitInput, 6, 0, 1, 3);

            var closeAllPendingButton = CreateCloseAllPendingButton();
            grid.AddChild(closeAllPendingButton, 7, 0, 1, 3);

            var closeAllOpenButton = CreateCloseAllOpenButton();
            grid.AddChild(closeAllOpenButton, 8, 0, 1, 3);

            contentPanel.AddChild(grid);

            return contentPanel;
        }

        private Button CreateMarketTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button 
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceMarket(tradeType);

            return tradeButton;
        }

        private Button CreateStopTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button 
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceStop(tradeType);

            return tradeButton;
        }

        private Button CreateLimitTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button 
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceLimit(tradeType);

            return tradeButton;
        }

        private ControlBase CreateCloseAllPendingButton()
        {
            var closeAllBorder = new Border 
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button 
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Pending",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllPending();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private ControlBase CreateCloseAllOpenButton()
        {
            var closeAllBorder = new Border 
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button 
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Open",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllOpen();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private Panel CreateInputWithLabel(string label, string defaultValue, string inputKey)
        {
            var stackPanel = new StackPanel 
            {
                Orientation = Orientation.Vertical,
                Margin = "0 10 0 0"
            };

            var textBlock = new TextBlock 
            {
                Text = label
            };

            var input = new TextBox 
            {
                Margin = "0 5 0 0",
                Text = defaultValue,
                Style = Styles.CreateInputStyle()
            };

            _inputMap.Add(inputKey, input);

            stackPanel.AddChild(textBlock);
            stackPanel.AddChild(input);

            return stackPanel;
        }

        private void PlaceMarket(TradeType tradeType)
        {
            var _vol_usable = 0.0;
            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                _vol_usable = Calc_UPT();
                var stopLossPips = Calc_SL();
                var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
                var _price_usable = GetValueFromInput(PriceInputKey, 0);

                if (_vol_usable <= 0)
                {
                    _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                    return;
                }
                for (int i = 0; i < _frag; i++)
                {
                    _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, _vol_usable, string.Empty, stopLossPips, takeProfitPips);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }

        }

        private void PlaceStop(TradeType tradeType)
        {
            var _vol_usable = 0.0;
            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                _vol_usable = Calc_UPT();
                var stopLossPips = Calc_SL();
                var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
                var _price_usable = GetValueFromInput(PriceInputKey, 0);

                if (_vol_usable <= 0)
                {
                    _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                    return;
                }
                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceStopOrderAsync(tradeType, _symbol.Name, _vol_usable, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }

        }

        private void PlaceLimit(TradeType tradeType)
        {
            var _vol_usable = 0.0;
            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                _vol_usable = Calc_UPT();
                var stopLossPips = Calc_SL();
                var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
                var _price_usable = GetValueFromInput(PriceInputKey, 0);

                if (_vol_usable <= 0)
                {
                    _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                    return;
                }

                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceLimitOrderAsync(tradeType, _symbol.Name, _vol_usable, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }

        }

        private double Calc_UPT()
        {
            var _frag = GetValueFromInput(FragInputKey, 0);
            var _RiskPercent = GetValueFromInput(RiskInputKey, 0);
            var _SL = GetValueFromInput(StopLossInputKey, 0);

            double costPerPip = (double)((int)(_robot.Symbol.PipValue * 10000000)) / 100;

            double baseNumber = _robot.Account.Balance;

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

            var result = _robot.Symbol.QuantityToVolumeInUnits(sizeInLots);

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

            var _units = Math.Round(result / _frag, 2);

            return _units;
        }

        private double Calc_SL()
        {
            var _FromInput = GetValueFromInput(StopLossInputKey, 0);
            var _Price = (_robot.Symbol.Bid + _robot.Symbol.Ask) / 2;
            var _BarsHL = 0.0;
            var _Distance = 0.0;
            var trend = _robot.Bars.ClosePrices.LastValue > TrendMA.Result.LastValue ? true : false;
            var fast = FastMA.Result.LastValue > SlowMA.Result.LastValue ? true : false;
            if (trend && fast)
            {
                _BarsHL = _robot.Bars.LowPrices.LastValue;
                _Distance = (_Price - _BarsHL) * _robot.Symbol.PipSize;
            }
            else if (!trend && !fast)
            {
                _BarsHL = _robot.Bars.HighPrices.LastValue;
                _Distance = (_BarsHL - _Price) * _robot.Symbol.PipSize;
            }

            return _Distance;
        }

        private double GetValueFromInput(string inputKey, double defaultValue)
        {
            double value;

            return double.TryParse(_inputMap[inputKey].Text, out value) ? value : defaultValue;
        }

        private void CloseAllPending()
        {
            foreach (var pending in _robot.PendingOrders)
                _robot.CancelPendingOrderAsync(pending);
        }

        private void CloseAllOpen()
        {
            foreach (var position in _robot.Positions)
                _robot.ClosePositionAsync(position);
        }
    }

    public static class Styles
    {
        public static Style CreatePanelBackgroundStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.CornerRadius, 3);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#292929"), 0.85m), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.85m), ControlState.LightTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#3C3C3C"), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#C3C3C3"), ControlState.LightTheme);
            style.Set(ControlProperty.BorderThickness, new Thickness(1));

            return style;
        }

        public static Style CreateCommonBorderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.12m), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#000000"), 0.12m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateHeaderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#FFFFFF", 0.70m), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#000000", 0.65m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateInputStyle()
        {
            var style = new Style(DefaultStyles.TextBoxStyle);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#1A1A1A"), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#111111"), ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#E7EBED"), ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#D6DADC"), ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.CornerRadius, 3);
            return style;
        }

        public static Style CreateBuyButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#009345"), Color.FromHex("#10A651"));
        }

        public static Style CreateSellButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        public static Style CreateCloseButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        private static Style CreateButtonStyle(Color color, Color hoverColor)
        {
            var style = new Style(DefaultStyles.ButtonStyle);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.LightTheme);
            return style;
        }

        private static Color GetColorWithOpacity(Color baseColor, decimal opacity)
        {
            var alpha = (int)Math.Round(byte.MaxValue * opacity, MidpointRounding.AwayFromZero);
            return Color.FromArgb(alpha, baseColor);
        }
    }
}

 


@waym77

waym77
15 Sep 2021, 15:34 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

I recommend you to calculate the fractals by your self, instead of using cTrader fractals indicator, that way you will be sure about how it works and what kind of result it should give you.

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter("Fractal Period", DefaultValue = 5, MinValue = 5)]
        public int Period { get; set; }

        [Parameter("Volume", DefaultValue = 1000)]
        public double FirstVolume { get; set; }

        private Fractals _fractal;

        protected override void OnStart()
        {
            _fractal = Indicators.Fractals(Period);
        }

        protected override void OnBar()
        {
            if (double.IsNaN(_fractal.UpFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) <= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) < Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) > Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.UpFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }

            if (double.IsNaN(_fractal.DownFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) >= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) > Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) < Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.DownFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }
        }
    }
}

My sample uses cTrader fractals and if the next candle after fractal was an engulfing candle it executes the trade.

But I don't know how the cTrader fractals indicator works, so its better to calculate it by yourself or search and you might find some fractal indicators already developed by other community members.

Hi,

I have adapted the code from a bot to an indicator, however, I am struggling to get the logic working in the correct order. As I mentioned before: As soon as the latest bar closes and turns into Bar 1, there needs to have been a fractal on 1 and an engulfing on 0. This is only possible with fractal at 3.

 

Additionally, I need these signals to print further over the index so I can backtest it. 

For clarification, please see the image, code in question, and custom fractals indicator:

 

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class FractalMomentum : Indicator
    {
        [Parameter("Fractal Period", DefaultValue = 3, MinValue = 1)]
        public int Period { get; set; }

        [Parameter("Print Offset (Pips)", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 100.0, Step = 0.1)]
        public double _PO_Parameter { get; set; }

        private double _offset, _offset_calc;

        private CustomFractals _fractal;

        protected override void Initialize()
        {
            _fractal = Indicators.GetIndicator<CustomFractals>(Period);
        }

        public override void Calculate(int index)
        {
            _offset = _PO_Parameter * Symbol.PipValue;

            if (double.IsNaN(_fractal.UpFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) <= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) < Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) > Bars.OpenPrices.Last(Period))
            {
                _offset_calc = Bars.LowPrices.LastValue - _offset;
                Chart.DrawIcon("Sell", ChartIconType.DownTriangle, Bars.OpenTimes.LastValue, _offset_calc, Color.OrangeRed);
            }
            if (double.IsNaN(_fractal.DownFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) >= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) > Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) < Bars.OpenPrices.Last(Period))
            {
                _offset_calc = Bars.HighPrices.LastValue + _offset;
                Chart.DrawIcon("Buy", ChartIconType.UpTriangle, Bars.OpenTimes.LastValue, _offset_calc, Color.Green);
            }
        }
    }
}

--------------------

 

using cAlgo.API;


namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class CustomFractals : Indicator
    {
        [Parameter(DefaultValue = 3, MinValue = 1)]
        public int Period { get; set; }

        [Output("Up Fractal", LineColor = "Red", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries UpFractal { get; set; }

        [Output("Down Fractal", LineColor = "Green", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries DownFractal { get; set; }

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

            DrawUpFractal(index);
            DrawDownFractal(index);

        }

        private void DrawUpFractal(int index)
        {
            int period = Period % 2 == 0 ? Period - 1 : Period;
            int middleIndex = index - period / 2;
            double middleValue = Bars.HighPrices[middleIndex];

            bool up = true;

            for (int i = 0; i < period; i++)
            {
                if (middleValue < Bars.HighPrices[index - i])
                {
                    up = false;
                    break;
                }
            }
            if (up)
                UpFractal[middleIndex] = middleValue;

        }

        private void DrawDownFractal(int index)
        {
            int period = Period % 2 == 0 ? Period - 1 : Period;
            int middleIndex = index - period / 2;
            double middleValue = Bars.LowPrices[middleIndex];
            bool down = true;

            for (int i = 0; i < period; i++)
            {
                if (middleValue > Bars.LowPrices[index - i])
                {
                    down = false;
                    break;
                }
            }
            if (down)
                DownFractal[middleIndex] = middleValue;

        }


    }
}

 

Your help and advice is greatly appreciated, thanks.


@waym77

waym77
15 Sep 2021, 12:33

RE:

amusleh said:

I recommend you to calculate the fractals by your self, instead of using cTrader fractals indicator, that way you will be sure about how it works and what kind of result it should give you.

Try this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter("Fractal Period", DefaultValue = 5, MinValue = 5)]
        public int Period { get; set; }

        [Parameter("Volume", DefaultValue = 1000)]
        public double FirstVolume { get; set; }

        private Fractals _fractal;

        protected override void OnStart()
        {
            _fractal = Indicators.Fractals(Period);
        }

        protected override void OnBar()
        {
            if (double.IsNaN(_fractal.UpFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) <= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) < Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) > Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.UpFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }

            if (double.IsNaN(_fractal.DownFractal.Last(Period)) == false && Bars.ClosePrices.Last(Period - 1) >= Bars.OpenPrices.Last(Period) && Bars.ClosePrices.Last(Period - 1) > Bars.OpenPrices.Last(Period - 1) && Bars.ClosePrices.Last(Period) < Bars.OpenPrices.Last(Period))
            {
                Print(_fractal.DownFractal.Last(Period));

                foreach (var position in Positions)
                {
                    if (position.SymbolName == SymbolName && position.Label == "Fractal")
                        ClosePosition(position);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, FirstVolume, "Fractal", null, null, null, false);
            }
        }
    }
}

My sample uses cTrader fractals and if the next candle after fractal was an engulfing candle it executes the trade.

But I don't know how the cTrader fractals indicator works, so its better to calculate it by yourself or search and you might find some fractal indicators already developed by other community members.

Hi amusleh,

 

Thanks for the code suggestions, I'll have a look at it now.

The cTrader fractals has a natural limitation of min 5 periods, which didn't work for me. As a result, I am already using a custom fractal system I found on the community forum.

 

Basic fractals, but with a min limit of < 5.

 

Thanks again.


@waym77

waym77
08 Sep 2021, 09:56

RE:

amusleh said:

Hi,

You should use a loop to execute multiple orders, try this:

using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EasyStop : Robot
    {
        [Parameter("Vertical Position", Group = "Panel alignment", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment PanelVerticalAlignment { get; set; }

        [Parameter("Horizontal Position", Group = "Panel alignment", DefaultValue = HorizontalAlignment.Left)]
        public HorizontalAlignment PanelHorizontalAlignment { get; set; }

        [Parameter("Default Price", Group = "Default trade parameters", DefaultValue = 1.17)]
        public double DefaultPrice { get; set; }

        [Parameter("Default Lots", Group = "Default trade parameters", DefaultValue = 0.01)]
        public double DefaultLots { get; set; }

        [Parameter("Default Fragmentation", Group = "Default trade parameters", DefaultValue = 1)]
        public double DefaultFrag { get; set; }

        [Parameter("Default Take Profit (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultTakeProfitPips { get; set; }

        [Parameter("Default Stop Loss (pips)", Group = "Default trade parameters", DefaultValue = 10)]
        public double DefaultStopLossPips { get; set; }

        protected override void OnStart()
        {
            var tradingPanel = new TradingPanel(this, Symbol, DefaultPrice, DefaultFrag, DefaultLots, DefaultStopLossPips, DefaultTakeProfitPips);

            var border = new Border
            {
                VerticalAlignment = PanelVerticalAlignment,
                HorizontalAlignment = PanelHorizontalAlignment,
                Style = Styles.CreatePanelBackgroundStyle(),
                Margin = "20 40 20 20",
                Width = 225,
                Child = tradingPanel
            };

            Chart.AddControl(border);
        }
    }

    public class TradingPanel : CustomControl
    {
        private const string LotsInputKey = "LotsKey";
        private const string PriceInputKey = "PriceKey";
        private const string FragInputKey = "FragKey";
        private const string TakeProfitInputKey = "TPKey";
        private const string StopLossInputKey = "SLKey";
        private readonly IDictionary<string, TextBox> _inputMap = new Dictionary<string, TextBox>();
        private readonly Robot _robot;
        private readonly Symbol _symbol;

        public TradingPanel(Robot robot, Symbol symbol, double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            _robot = robot;
            _symbol = symbol;
            AddChild(CreateTradingPanel(defaultPrice, defaultFrag, defaultLots, defaultStopLossPips, defaultTakeProfitPips));
        }

        private ControlBase CreateTradingPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var mainPanel = new StackPanel();

            var header = CreateHeader();
            mainPanel.AddChild(header);

            var contentPanel = CreateContentPanel(defaultPrice, defaultFrag, defaultLots, defaultStopLossPips, defaultTakeProfitPips);
            mainPanel.AddChild(contentPanel);

            return mainPanel;
        }

        private ControlBase CreateHeader()
        {
            var headerBorder = new Border
            {
                BorderThickness = "0 0 0 1",
                Style = Styles.CreateCommonBorderStyle()
            };

            var header = new TextBlock
            {
                Text = "Quick Trading Panel",
                Margin = "10 7",
                Style = Styles.CreateHeaderStyle()
            };

            headerBorder.Child = header;
            return headerBorder;
        }

        private StackPanel CreateContentPanel(double defaultPrice, double defaultFrag, double defaultLots, double defaultStopLossPips, double defaultTakeProfitPips)
        {
            var contentPanel = new StackPanel
            {
                Margin = 10
            };
            var grid = new Grid(9, 3);
            grid.Columns[1].SetWidthInPixels(5);

            var sellmarketButton = CreateMarketTradeButton("MARKET SELL", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellmarketButton, 0, 0);

            var buymarketButton = CreateMarketTradeButton("MARKET BUY", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buymarketButton, 0, 2);

            var sellstopButton = CreateStopTradeButton("SELL STOP", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(sellstopButton, 1, 0);

            var buystopButton = CreateStopTradeButton("BUY STOP", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buystopButton, 1, 2);

            var selllimitButton = CreateLimitTradeButton("SELL LIMIT", Styles.CreateSellButtonStyle(), TradeType.Sell);
            grid.AddChild(selllimitButton, 3, 0);

            var buylimitButton = CreateLimitTradeButton("BUY LIMIT", Styles.CreateBuyButtonStyle(), TradeType.Buy);
            grid.AddChild(buylimitButton, 3, 2);

            var priceInput = CreateInputWithLabel("Pending Price", defaultPrice.ToString("F2"), PriceInputKey);
            grid.AddChild(priceInput, 4, 0);

            var fragInput = CreateInputWithLabel("Order Fragmentation", defaultFrag.ToString("F2"), FragInputKey);
            grid.AddChild(fragInput, 4, 2);

            var lotsInput = CreateInputWithLabel("Quantity (Lots)", defaultLots.ToString("F2"), LotsInputKey);
            grid.AddChild(lotsInput, 5, 0, 1, 3);

            var stopLossInput = CreateInputWithLabel("Stop Loss (Pips)", defaultStopLossPips.ToString("F1"), StopLossInputKey);
            grid.AddChild(stopLossInput, 6, 0);

            var takeProfitInput = CreateInputWithLabel("Take Profit (Pips)", defaultTakeProfitPips.ToString("F1"), TakeProfitInputKey);
            grid.AddChild(takeProfitInput, 6, 2);

            var closeAllPendingButton = CreateCloseAllPendingButton();
            grid.AddChild(closeAllPendingButton, 7, 0, 1, 3);

            var closeAllOpenButton = CreateCloseAllOpenButton();
            grid.AddChild(closeAllOpenButton, 8, 0, 1, 3);

            contentPanel.AddChild(grid);

            return contentPanel;
        }

        private Button CreateMarketTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceMarket(tradeType);

            return tradeButton;
        }

        private Button CreateStopTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceStop(tradeType);

            return tradeButton;
        }

        private Button CreateLimitTradeButton(string text, Style style, TradeType tradeType)
        {
            var tradeButton = new Button
            {
                Text = text,
                Style = style,
                Height = 25
            };

            tradeButton.Click += args => PlaceLimit(tradeType);

            return tradeButton;
        }

        private ControlBase CreateCloseAllPendingButton()
        {
            var closeAllBorder = new Border
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Pending",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllPending();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private ControlBase CreateCloseAllOpenButton()
        {
            var closeAllBorder = new Border
            {
                Margin = "0 10 0 0",
                BorderThickness = "0 1 0 0",
                Style = Styles.CreateCommonBorderStyle()
            };

            var closeButton = new Button
            {
                Style = Styles.CreateCloseButtonStyle(),
                Text = "Close All Open",
                Margin = "0 10 0 0"
            };

            closeButton.Click += args => CloseAllOpen();
            closeAllBorder.Child = closeButton;

            return closeAllBorder;
        }

        private Panel CreateInputWithLabel(string label, string defaultValue, string inputKey)
        {
            var stackPanel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                Margin = "0 10 0 0"
            };

            var textBlock = new TextBlock
            {
                Text = label
            };

            var input = new TextBox
            {
                Margin = "0 5 0 0",
                Text = defaultValue,
                Style = Styles.CreateInputStyle()
            };

            _inputMap.Add(inputKey, input);

            stackPanel.AddChild(textBlock);
            stackPanel.AddChild(input);

            return stackPanel;
        }

        private void PlaceMarket(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);
            var lots = GetValueFromInput(LotsInputKey, 0);

            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.ExecuteMarketOrderAsync(tradeType, _symbol.Name, _volume_units, string.Empty, stopLossPips, takeProfitPips);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private void PlaceStop(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var lots = GetValueFromInput(LotsInputKey, 0);
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);

            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceStopOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private void PlaceLimit(TradeType tradeType)
        {
            var _vol_usable = Calc_LPT();
            var stopLossPips = GetValueFromInput(StopLossInputKey, 0);
            var takeProfitPips = GetValueFromInput(TakeProfitInputKey, 0);
            var _price_usable = GetValueFromInput(PriceInputKey, 0);

            var _volume_units = _symbol.QuantityToVolumeInUnits(_vol_usable);
            var lots = GetValueFromInput(LotsInputKey, 0);
            if (lots <= 0)
            {
                _robot.Print(string.Format("{0} failed, invalid Lots", tradeType));
                return;
            }

            var _frag = GetValueFromInput(FragInputKey, 0);
            if (_frag >= 1)
            {
                for (int i = 0; i < _frag; i++)
                {
                    _robot.PlaceLimitOrderAsync(tradeType, _symbol.Name, _volume_units, _price_usable, string.Empty, stopLossPips, takeProfitPips, null);
                }
            }
            else if (_frag < 1)
            {
                _robot.Print(string.Format("{0} failed, invalid Frag", tradeType));
                return;
            }
        }

        private double Calc_LPT()
        {
            var _lots = GetValueFromInput(LotsInputKey, 0);
            var _frag = GetValueFromInput(FragInputKey, 0);
            var result = Math.Round(_lots / _frag, 2);
            return result;
        }

        private double GetValueFromInput(string inputKey, double defaultValue)
        {
            double value;

            return double.TryParse(_inputMap[inputKey].Text, out value) ? value : defaultValue;
        }

        private void CloseAllPending()
        {
            foreach (var pending in _robot.PendingOrders)
                _robot.CancelPendingOrderAsync(pending);
        }

        private void CloseAllOpen()
        {
            foreach (var position in _robot.Positions)
                _robot.ClosePositionAsync(position);
        }
    }

    public static class Styles
    {
        public static Style CreatePanelBackgroundStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.CornerRadius, 3);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#292929"), 0.85m), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.85m), ControlState.LightTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#3C3C3C"), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, Color.FromHex("#C3C3C3"), ControlState.LightTheme);
            style.Set(ControlProperty.BorderThickness, new Thickness(1));

            return style;
        }

        public static Style CreateCommonBorderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#FFFFFF"), 0.12m), ControlState.DarkTheme);
            style.Set(ControlProperty.BorderColor, GetColorWithOpacity(Color.FromHex("#000000"), 0.12m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateHeaderStyle()
        {
            var style = new Style();
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#FFFFFF", 0.70m), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, GetColorWithOpacity("#000000", 0.65m), ControlState.LightTheme);
            return style;
        }

        public static Style CreateInputStyle()
        {
            var style = new Style(DefaultStyles.TextBoxStyle);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#1A1A1A"), ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#111111"), ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#E7EBED"), ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, Color.FromHex("#D6DADC"), ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.CornerRadius, 3);
            return style;
        }

        public static Style CreateBuyButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#009345"), Color.FromHex("#10A651"));
        }

        public static Style CreateSellButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        public static Style CreateCloseButtonStyle()
        {
            return CreateButtonStyle(Color.FromHex("#F05824"), Color.FromHex("#FF6C36"));
        }

        private static Style CreateButtonStyle(Color color, Color hoverColor)
        {
            var style = new Style(DefaultStyles.ButtonStyle);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.DarkTheme);
            style.Set(ControlProperty.BackgroundColor, color, ControlState.LightTheme);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.DarkTheme | ControlState.Hover);
            style.Set(ControlProperty.BackgroundColor, hoverColor, ControlState.LightTheme | ControlState.Hover);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.DarkTheme);
            style.Set(ControlProperty.ForegroundColor, Color.FromHex("#FFFFFF"), ControlState.LightTheme);
            return style;
        }

        private static Color GetColorWithOpacity(Color baseColor, decimal opacity)
        {
            var alpha = (int)Math.Round(byte.MaxValue * opacity, MidpointRounding.AwayFromZero);
            return Color.FromArgb(alpha, baseColor);
        }
    }
}

 

Hi amusleh,

 

That's brilliant, thank you so much!

 

If you wouldn't mind, I have another thread regarding something new I'm trying in this same bot: 

 


@waym77

waym77
16 Aug 2021, 16:22

RE:

amusleh said:

Hi,

When you are using a custom indicator on a cBot you must pass a value for all of the indicator parameters, for TDI you can use it like this:

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class TDISystem : Robot
    {
        //parameters

        private TradersDynamicIndex _TDI;

        protected override void OnStart()
        {
            _TDI = Indicators.GetIndicator<TradersDynamicIndex>(Bars.ClosePrices, 13, 2, 7, 34, 2, MovingAverageType.Simple, MovingAverageType.Simple);
        }

        protected override void OnBar()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

The parameters you pass must be in same order that is defined in indicator.

Hi,

This is perfect, thanks!


@waym77

waym77
28 Jul 2021, 16:42

RE:

amusleh said:

Hi,

Can you post the cBot full code?

Hi,

 

Thanks for the reply, but it's not necessary. I set the stop at executing to null and it worked.

Sharing just in case someone has the same problem. 


@waym77

waym77
22 Jul 2021, 14:40

RE:

PanagiotisCharalampous said:

Hi waym77,

Is there a way I can get the Renko to be calculated via (Bid + Ask) / 2?

No that is not possible

Or if this is not possible, would it simply be best to widen the Stop to 11 pips?

What problem are you trying to solve here? Why do you need to change the way you trade the Ask prices based on what the Bid prices do?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

 

The problem I'm trying to solve is that the Sell trade opened correctly but hit my stop loss before continuing with the downward movement. If I had widened this stop to 11, the ask would not have reached my Stop. Since the green bar did not print, it means the bid never reached the Stop, and the ask barely did. The spread between these two is what caused this unnecessary stop loss.


@waym77

waym77
22 Jul 2021, 13:51

RE:

Spotware said:

Hi waym77,

Renko bars are formed by bid prices. Sell positions are closed by Ask prices. Probably the Bid price never reached above 1.72800.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Thanks for the reply, it makes sense now why this happened!

 

On to attempting to fix this, which has led me to another question:

Is there a way I can get the Renko to be calculated via (Bid + Ask) / 2?

Or if this is not possible, would it simply be best to widen the Stop to 11 pips?


@waym77