Replies

samachua2011
07 Oct 2022, 17:09

RE:

 

I have attached a simple cbot below where we need to pass the indicator values to the cbot. How can we go about writing the (if statements) to execute Long/Short positions on the cbot? Below is a simplified cbot and the indicator source code:

cBot

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.None)]
    public class HeikenashiSmooth : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        public HeikinAshiSmoothed has;

        protected override void OnStart()
        {
            has = Indicators.GetIndicator<HeikinAshiSmoothed>(5, MovingAverageType.Exponential);

            // Put your initialization logic here
        }

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

        protected override void OnBar()
        {
            ///ExecuteMarketOrder(TradeType.Buy, SymbolName, VolumeInUnits, label);

            ///ExecuteMarketOrder(TradeType.Sell, SymbolName, VolumeInUnits, label);
        }

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

 

Indicator:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.FullAccess)]
    public class HeikinAshiSmoothed : Indicator
    {
        [Parameter(DefaultValue = 5, MinValue = 1)]
        public int Periods { get; set; }

        [Parameter("MA Type1", DefaultValue = MovingAverageType.Exponential)]
        public MovingAverageType MAType { get; set; }

        public MovingAverage maOpen;
        public MovingAverage maClose;
        public MovingAverage maHigh;
        public MovingAverage maLow;

        public IndicatorDataSeries haClose;
        public IndicatorDataSeries haOpen;

        protected override void Initialize()
        {
            maOpen = Indicators.MovingAverage(MarketSeries.Open, Periods, MAType);
            maClose = Indicators.MovingAverage(MarketSeries.Close, Periods, MAType);
            maHigh = Indicators.MovingAverage(MarketSeries.High, Periods, MAType);
            maLow = Indicators.MovingAverage(MarketSeries.Low, Periods, MAType);
            haOpen = CreateDataSeries();
            haClose = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            double haHigh;
            double haLow;
            Colors Color;

            if (index > 0 && !double.IsNaN(maOpen.Result[index - 1]))
            {
                haOpen[index] = (haOpen[index - 1] + haClose[index - 1]) / 2;
                haClose[index] = (maOpen.Result[index] + maClose.Result[index] + 
                maHigh.Result[index] + maLow.Result[index]) / 4;
                haHigh = Math.Max(maHigh.Result[index], Math.Max(haOpen[index], haClose[index]));
                haLow = Math.Min(maLow.Result[index], Math.Min(haOpen[index], haClose[index]));
                Color = (haOpen[index] > haClose[index]) ? Colors.Red : Colors.LimeGreen;
                ChartObjects.DrawLine("BarHA" + index, index, haOpen[index], index, 
                haClose[index], Color, 5, LineStyle.Solid);
                ChartObjects.DrawLine("LineHA" + index, index, haHigh, index, haLow, Color, 1, 
                LineStyle.Solid);
            }
            else if (!double.IsNaN(maOpen.Result[index]))
            {
                haOpen[index] = (maOpen.Result[index] + maClose.Result[index]) / 2;
                haClose[index] = (maOpen.Result[index] + maClose.Result[index] + 
                maHigh.Result[index] + maLow.Result[index]) / 4;
                haHigh = maHigh.Result[index];
                haLow = maLow.Result[index];
            }
        }
    }
}

@samachua2011

samachua2011
27 Sep 2022, 11:28

Such language is really not necessary. We will manage on our own


@samachua2011

samachua2011
27 Sep 2022, 09:55

RE:

PanagiotisCharalampous said:

Hi Samuel,

It is not very clear to me what you are trying to do. The position id is available in every position and all accouint positions are accessible from anywhere in the cBot. What is the problem you are trying to solve here?

 Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

We are trying to set Take Profit levels in a Reward Manager cbot where if a certain position is taken for example short on EURJPY 1 lot:

  • Take Profit 1   10 pips   50%
  • Take Profit 2   15 pips   30%
  • Take Profit 3   20 pips   20%

In order to do this, we need to reference the position id. However, since we want the bot to take multiple trades on its own, one cannot keep adding the position id manually to the bot each time a trade is taken hence the need to automate this process. What we want to do is have a command that picks the position id "PID" each time the cbot automatically takes a short/long position so that the cbot auto calculates the take profit levels and manages the position.

How do we code the "DefaultPositionIdParameterValue" term referenced on the snippet of code below "Snippet 1" to pick the Position id "PID" from the Execute Market Order in the code below referenced "Snippet2":

Snippet 1

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PriceActionBotGuide2Reward : Robot
    {
        private const string DefaultPositionIdParameterValue = "PID";

        [Parameter("Position Id", Group = "Position", DefaultValue = 
        DefaultPositionIdParameterValue)]
        public string PositionId { get; set; }

 

Snippet 2

ExecuteMarketOrder(type, SymbolName, volumeInUnits, Label, SL, TP);
Print(LastResult, Position.Id);

 


@samachua2011

samachua2011
27 Sep 2022, 09:24

RE:

PanagiotisCharalampous said:

Hi Samuel,

Can you make your question more specific? If you don't know how to do this, better assing the job to a professional.

Best Regards,

Panagiotis 

Join us onTelegram andFacebook

Hi Panagiotis,

Trying to be a bit more specific, we want to reference the Smooth Heiken-Ashi Indicator into the cbot whose source code I have shared below such that:

  • when the Smooth Heiken Ashi bars turn Red, the bot executes a Short trade AND
  • when the Smooth Heiken-Ashi bars turn Green, the bot executes a Long trade.

What we need is to know whether it is easier to:

  • reference the Smooth Heiken-Ashi Indicator within the bot allowing it to get signals to execute trades OR
  • move the indicator code into the cbot and refrain from referencing the indicator thereby enabling the cbot make the trades without reference to any indicator

What we also need to know is:

  • In case we go with the 1st option of referencing the indicator, how would the cbot code shared below be written to reference the indicator allowing it to get signals to execute trades.
  • In case the easier option is to move the indicator code into the cbot code below, how would the cbot code shared below be written allowing it to get signals to execute trades.

On the code, I have referenced the area that is giving us a challenge i.e. [Problematic area starts here - Problematic area ends here]

Kindly assist.

Best Regards,

Samuel Machua.

 

//////////////////////////////////////////////////////////////////////////////////////////////////////////
///Assemblies
//////////////////////////////////////////////////////////////////////////////////////////////////////////

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PriceActionBot : Robot
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Definitions of Enumerators
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Risk Manager Enumerator
        /// </summary>
        public enum ENUM_TP_TYPE
        {
            Fixed = 0,
            RiskRatio = 1
        }

        /// <summary>
        /// Cash Manager Enumerators
        /// </summary>
        public enum ENUM_RISK_SOURCE
        {
            Equity = 0,
            Balance = 1
        }
        public enum ENUM_LOT_TYPE
        {
            Fixed_Lot = 0,
            Percent = 1
            // Fixed_Amount = 2
        }

        /// <summary>
        /// Position Manager1 Enumerator
        /// </summary>
        public enum ENUM_BAR_CHECK
        {
            Current_Bar = 0,
            Formed_Bar = 1
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///User Defined Parameters
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        #region Smooth Heiken-Ashi Parameters
        [Parameter("Period", Group = "Smooth Heikenashi Parameters", DefaultValue = 5, MinValue = 1)]
        public int Periods { get; set; }

        [Parameter("MA Type", Group = "Smooth Heikenashi Parameters", DefaultValue = MovingAverageType.Exponential)]
        public MovingAverageType MAType { get; set; }
        #endregion

        #region Input Cash Manager Parameters
        [Parameter("Lot Type", Group = "Cash Manager", DefaultValue = ENUM_LOT_TYPE.Percent)]
        public ENUM_LOT_TYPE lotType { get; set; }

        [Parameter("Risk Source", Group = "Cash Manager", DefaultValue = ENUM_RISK_SOURCE.Balance)]
        public ENUM_RISK_SOURCE riskSource { get; set; }

        [Parameter("Risk/Lot Value", Group = "Cash Manager", MinValue = 0.1)]
        public double risk { get; set; }
        #endregion

        #region Input Position Manager Parameters
        [Parameter("Bar to Check", Group = "Position Manager", DefaultValue = ENUM_BAR_CHECK.Formed_Bar)]
        public ENUM_BAR_CHECK barCheck { get; set; }

        [Parameter("Label", Group = "Position Manager", DefaultValue = "Price Action Bot")]
        public string Label { get; set; }

        [Parameter("SLoss * (ATR Value)", Group = "Position Manager", MinValue = 1)]
        public double SL { get; set; }

        [Parameter("Take Profit type", Group = "Position Manager", DefaultValue = ENUM_TP_TYPE.Fixed)]
        public ENUM_TP_TYPE tpType { get; set; }

        [Parameter("Take Profit value", Group = "Position Manager", DefaultValue = 0)]
        public double TP { get; set; }

        [Parameter("Close on the opposite signal", Group = "Position Manager", DefaultValue = true)]
        public bool oppositeClose { get; set; }

        [Parameter("Only one trade in one direction", Group = "Position Manager", DefaultValue = true)]
        public bool onlyOne { get; set; }

        [Parameter("Use Reverse Trade", Group = "Position Manager", DefaultValue = true)]
        public bool reverseTrade { get; set; }
        #endregion

        #region Input Risk Manager1
        [Parameter("Max Spread", DefaultValue = 2.0, MinValue = -5.0, Group = "Risk Manager1")]
        public double MaxSpread { get; set; }

        [Parameter("Days", DefaultValue = "Saturday,Sunday", Group = "Risk Manager1")]
        public string Days { get; set; }

        [Parameter("Start Time", DefaultValue = "07:00:00", Group = "Risk Manager1")]
        public string StartTime { get; set; }

        [Parameter("End Time", DefaultValue = "16:00:00", Group = "Risk Manager1")]
        public string EndTime { get; set; }
        #endregion

        #region Risk Manager2 Parameters
        [Parameter("Include Trailing Stop", DefaultValue = true, Group = "Risk Manager2")]
        public bool IncludeTrailingStop { get; set; }

        [Parameter("Trailing Stop Trigger (pips)", MinValue = 0, MaxValue = 500, Step = 1, Group = "Risk Manager2")]
        public int TrailingStopTrigger { get; set; }

        [Parameter("Trailing Stop Step (pips)", MinValue = 0, MaxValue = 500, Step = 1, Group = "Risk Manager2")]
        public int TrailingStopStep { get; set; }
        #endregion

        #region Risk Manager3 Parameters
        [Parameter("Use BreakEven", Group = "Risk Manager3", DefaultValue = false)]
        public bool UseBE { get; set; }

        [Parameter("BE Start (pips)", Group = "Risk Manager3", DefaultValue = 10)]
        public double BEStart { get; set; }

        [Parameter("BE Profit (pips)", Group = "Risk Manager3", DefaultValue = 0)]
        public double BEProfit { get; set; }
        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Private & Public Call Events
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Risk Manager1 Private & Public call arguments
        /// </summary>
        private AverageTrueRange atr;
        private List<DayOfWeek> _pauseDays;
        private TimeSpan _startTime, _endTime;
        private bool _isPaused;
        string label = "Spread Test";

        /// <summary>
        /// Risk Manager2 Private & Public call arguments
        /// </summary>

        /// <summary>
        /// Smooth Heiken Ashi Private & Public call arguments
        /// </summary>
        public HeikinAshiSmoothed has;
        public IndicatorDataSeries haClose;
        public IndicatorDataSeries haOpen;

        // Problematic area begins here

        protected override void OnStart()
        {
            /// <summary>
            /// Smooth Heiken Ashi arguments
            /// </summary>

            /// <summary>
            /// Stop Loss arguments with ATR
            /// </summary>
            atr = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
            var PrevATR = Math.Round(atr.Result.Last(1) / Symbol.PipSize);

            /// <summary>
            /// Risk Manager1 arguments
            /// </summary>
            _pauseDays = Days.Split(',').Select(day => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), day)).ToList();

            if (TimeSpan.TryParse(StartTime, CultureInfo.InvariantCulture, out _startTime) == false)
            {
                Print("Invalid StartTime");
                Stop();
            }

            if (TimeSpan.TryParse(EndTime, CultureInfo.InvariantCulture, out _endTime) == false)
            {
                Print("Invalid EndTime");
                Stop();
            }

            Timer.Start(1);

        }

        /// <summary>
        /// Risk Manager1 arguments
        /// </summary>
        protected override void OnTimer()
        {
            if (_pauseDays.Contains(Server.Time.DayOfWeek) && Server.Time.TimeOfDay >= _startTime && Server.Time.TimeOfDay <= _endTime)
            {
                _isPaused = true;
            }

            _isPaused = false;
        }


        protected override void OnTick()
        {
            /// <summary>
            /// Risk Manager2 arguments
            /// </summary>
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }

            /// <summary>
            /// Risk Manager3 arguments
            /// </summary>
            if (UseBE)
                BreakEven();

            //buy & sell command
            //sell

            {
                if (oppositeClose)
                {
                    CloseOrders(TradeType.Buy);
                }
            }

            //buy

            {
                if (oppositeClose)
                {
                    CloseOrders(TradeType.Sell);
                }
            }
        }

        // Problematic area ends here

        void CloseOrders(TradeType type)
        {
            if (reverseTrade)
                type = type == TradeType.Buy ? TradeType.Sell : TradeType.Buy;

            foreach (var pos in Positions.FindAll(Label, SymbolName, type))
            {
                ClosePosition(pos);
            }
        }

        bool CheckOrder(TradeType type)
        {
            if (reverseTrade)
                type = type == TradeType.Buy ? TradeType.Sell : TradeType.Buy;

            if (Positions.Find(Label, SymbolName, type) != null)
                return false;
            return true;
        }

        void OpenOrder(TradeType type)
        {
            if (reverseTrade)
                type = type == TradeType.Buy ? TradeType.Sell : TradeType.Buy;

            double op;
            double tp = tpType == ENUM_TP_TYPE.Fixed ? TP : SL * TP;
            double sl;

            double source = riskSource == ENUM_RISK_SOURCE.Balance ? Account.Balance : Account.Equity;

            double volumeInUnits = 0;
            if (lotType == ENUM_LOT_TYPE.Fixed_Lot)
                volumeInUnits = Symbol.QuantityToVolumeInUnits(risk);
            else
                volumeInUnits = CalculateVolume(SL, risk, source);

            if (volumeInUnits == -1)
                return;
            ExecuteMarketOrder(type, SymbolName, volumeInUnits, Label, (Math.Round(atr.Result.Last(1) / Symbol.PipSize)) * SL, TP);
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Cash Manager
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        private double CalculateVolume(double stopLossPips, double riskSize, double source)
        {
            // source = Account.Balance or Account.Equity
            double riskPerTrade = source * riskSize / 100;
            double totalPips = stopLossPips;

            double _volume;
            double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);
            if (exactVolume >= Symbol.VolumeInUnitsMin)
            {
                _volume = Symbol.NormalizeVolumeInUnits(exactVolume);
            }
            else
            {
                _volume = -1;
                Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
            }
            return _volume;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Risk Managers
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Risk Manager2 arguments
        /// </summary>
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(Label, SymbolName, TradeType.Sell);
            foreach (var position in sellPositions)
            {
                double distance = position.EntryPrice - Symbol.Ask;
                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Ask + TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, (position.TakeProfit.HasValue ? position.TakeProfit.GetValueOrDefault() : (double?)null));
                }
            }

            var buyPositions = Positions.FindAll(Label, SymbolName, TradeType.Buy);
            foreach (var position in buyPositions)
            {
                double distance = Symbol.Bid - position.EntryPrice;
                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

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

        /// <summary>
        /// Risk Manager3 arguments
        /// </summary>
        private void BreakEven()
        {
            if (!UseBE)
                return;

            foreach (var pos in Positions.FindAll(Label, SymbolName))
            {
                if (pos.TradeType == TradeType.Buy)
                {
                    if (Symbol.Ask >= pos.EntryPrice + BEStart * Symbol.PipSize && (pos.StopLoss < pos.EntryPrice + BEProfit * Symbol.PipSize || pos.StopLoss == null))
                    {
                        ModifyPosition(pos, pos.EntryPrice + BEProfit * Symbol.PipSize, pos.TakeProfit);
                    }
                }
                if (pos.TradeType == TradeType.Sell)
                {
                    if (Symbol.Bid <= pos.EntryPrice - BEStart * Symbol.PipSize && (pos.StopLoss > pos.EntryPrice - BEProfit * Symbol.PipSize || pos.StopLoss == null))
                    {
                        ModifyPosition(pos, pos.EntryPrice + BEProfit * Symbol.PipSize, pos.TakeProfit);
                    }
                }
            }
        }

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

 


@samachua2011

samachua2011
24 Sep 2022, 12:21

RE:

PanagiotisCharalampous said:

Hi samachua2011,

You can do this but first you need to make the haClose and haOpen series public. Then you need to check them from the cBot.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi Panagiotis,

In the alternative, how would I move the logic from the indicator to a cbot?

 

Best Regards,

Samuel machua.


@samachua2011

samachua2011
23 Sep 2022, 13:38

Hi Panagiotis,

I have read your feedback and tried to implement the changes. See below and kindly advise.

Also, how can one reference this indicator in a cbot on the Parameters, On Start & On Tick/On Bar section

 

Best Regards,

Samuel Machua.

Indicator Code

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.FullAccess)]
    public class HeikinAshiSmoothed : Indicator
    {
        [Parameter(DefaultValue = 5, MinValue = 1)]
        public int Periods { get; set; }

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

        public MovingAverage maOpen;
        public MovingAverage maClose;
        public MovingAverage maHigh;
        public MovingAverage maLow;

        public IndicatorDataSeries haClose;
        public IndicatorDataSeries haOpen;

        protected override void Initialize()
        {
            maOpen = Indicators.MovingAverage(MarketSeries.Open, Periods, MAType);
            maClose = Indicators.MovingAverage(MarketSeries.Close, Periods, MAType);
            maHigh = Indicators.MovingAverage(MarketSeries.High, Periods, MAType);
            maLow = Indicators.MovingAverage(MarketSeries.Low, Periods, MAType);
            haOpen = CreateDataSeries();
            haClose = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            double haHigh;
            double haLow;
            Colors Color;

            if (index > 0 && !double.IsNaN(maOpen.Result[index - 1]))
            {
                haOpen[index] = (haOpen[index - 1] + haClose[index - 1]) / 2;
                haClose[index] = (maOpen.Result[index] + maClose.Result[index] + maHigh.Result[index] + maLow.Result[index]) / 4;
                haHigh = Math.Max(maHigh.Result[index], Math.Max(haOpen[index], haClose[index]));
                haLow = Math.Min(maLow.Result[index], Math.Min(haOpen[index], haClose[index]));
                Color = (haOpen[index] > haClose[index]) ? Colors.Red : Colors.LimeGreen;
                ChartObjects.DrawLine("BarHA" + index, index, haOpen[index], index, haClose[index], Color, 5, LineStyle.Solid);
                ChartObjects.DrawLine("LineHA" + index, index, haHigh, index, haLow, Color, 1, LineStyle.Solid);
            }
            else if (!double.IsNaN(maOpen.Result[index]))
            {
                haOpen[index] = (maOpen.Result[index] + maClose.Result[index]) / 2;
                haClose[index] = (maOpen.Result[index] + maClose.Result[index] + maHigh.Result[index] + maLow.Result[index]) / 4;
                haHigh = maHigh.Result[index];
                haLow = maLow.Result[index];

            }
        }
    }
}

 


@samachua2011