Topics

Forum Topics not found

Replies

cAlgo_Fanatic
26 Apr 2013, 15:44

// -------------------------------------------------------------------------------------------------
//
//    The "SampleTrailingbyLabel" cBot will trail an open position given the position Label. 
//    The user can set the variable "Trigger (pips)" 
//    which defines the point where the Stop Loss will start 
//    trailing the order. When the profit in pips is above or equal to "Trigger (pips)" 
//    the stop loss will start trailing the spot price.
//    Variable "Trailing Stop (pips)" defines the number of pips the Stop Loss trails the spot price by. 
//
// -------------------------------------------------------------------------------------------------

using System;
using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot("Sample Trailing Stop Robot")]
    public class SampleTrailingbyLabel : Robot
    {

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

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

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

        private bool _isTrigerred;
        
        protected override void OnStart()
        {
            Positions.Opened += PositionsOnOpened;
            ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, MyLabel);
        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            var position = args.Position;
            Print("Position {0} found, waiting for trigger.", position.Label);
        }

        protected override void OnTick()
        {
            var position = Positions.Find(MyLabel);
            
            if (position == null) return;

            if (position.TradeType == TradeType.Buy)
            {
                double distance = Symbol.Bid - position.EntryPrice;

                if (distance >= Trigger * Symbol.PipSize)
                {
                    if (!_isTrigerred)
                    {
                        _isTrigerred = true;
                        Print("Trailing Stop Loss triggered...");
                    }

                    double newStopLossPrice = Math.Round(Symbol.Bid - TrailingStop * Symbol.PipSize, Symbol.Digits);

                    if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                    {
                        ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                    }
                }
            }
            else
            {
                double distance = position.EntryPrice - Symbol.Ask;

                if (distance >= Trigger * Symbol.PipSize)
                {
                    if (!_isTrigerred)
                    {
                        _isTrigerred = true;
                        Print("Trailing Stop Loss triggered...");
                    }

                    double newStopLossPrice = Math.Round(Symbol.Ask + TrailingStop * Symbol.PipSize, Symbol.Digits);

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

    }
}

 


@cAlgo_Fanatic

cAlgo_Fanatic
26 Apr 2013, 15:01

You can copy the line (select the lline and press CTR + C) and paste it in a text editor like Notepad to see the whole error message. We are aware of this issue. There is no log file.


@cAlgo_Fanatic

cAlgo_Fanatic
26 Apr 2013, 11:31

Please see this sample for Max DrawDown.

In the example this is the function that calculates it which is called when the position closes, in the OnPositionClosed event:

        private void GetMaxDrawDown()
        {
            peak = Math.Max(peak, Account.Balance);
            Array.Resize(ref drawdown, drawdown.Length + 1);
            int i = drawdown.Length - 1;
            drawdown[i] = (peak - Account.Balance) / peak * 100;

            for (i = 0; i < drawdown.Length; i++)
                maxDrawdown = Math.Max(maxDrawdown, drawdown[i]);

            Print("Max DrawDown = {0}", Math.Round(maxDrawdown, 2));
            
        }

 


@cAlgo_Fanatic

cAlgo_Fanatic
26 Apr 2013, 11:26

This is the sample martingale robot included in the cAlgo with the calculation of Max Draw Down.

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

namespace cAlgo.Robots
{
    [Robot]
    public class MaxDrawdown:Robot
    {
        [Parameter("Position Label", DefaultValue = "Martingale MaxDrawDown")]
        public string MyLabel { get; set; }

        [Parameter("Initial Volume", DefaultValue = 10000, MinValue = 0)]
        public int InitialVolume { get; set; }

        [Parameter("Stop Loss", DefaultValue = 40)]
        public int StopLoss { get; set; }

        [Parameter("Take Profit", DefaultValue = 40)]
        public int TakeProfit { get; set; }

        private Random random = new Random();

        private double peak;
        private List<double> drawdown = new List<double>();
        private double maxDrawdown;

        protected override void OnStart()
        {
            Positions.Closed += PositionsOnClosed;
            ExecuteOrder(InitialVolume, GetRandomTradeCommand());
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;
            if (position.Label != MyLabel) return;

            Print("Position labeled {0} has closed", position.Label);

            if (position.NetProfit > 0)
            {
                ExecuteOrder(InitialVolume, GetRandomTradeCommand());
            }
            else
            {                
                ExecuteOrder((int)position.Volume * 2, position.TradeType);
            }

            GetMaxDrawDown();
        }

        private void ExecuteOrder(int volume, TradeType tradeType)
        {
            ExecuteMarketOrder(tradeType, Symbol, volume, MyLabel, StopLoss, TakeProfit);
        }


        private void GetMaxDrawDown()
        {
            peak = Math.Max(peak, Account.Balance);
                        
            drawdown.Add((peak - Account.Balance) / peak * 100);
            drawdown.Sort();

            maxDrawdown = drawdown[drawdown.Count - 1];

            Print("Max DrawDown = {0}", Math.Round(maxDrawdown, 2));
            
        }

        protected override void OnError(Error error)
        {
            if (error.Code == ErrorCode.BadVolume)
                Stop();
        }

        private TradeType GetRandomTradeCommand()
        {
            return random.Next(2) == 0 ? TradeType.Buy : TradeType.Sell;
        }

    }
}

 


@cAlgo_Fanatic

cAlgo_Fanatic
26 Apr 2013, 09:28

This issue has been fixed with the new update which if is not available to you yet it will be by Monday. You can test it with a demo account on Spotware cTrader and cAlgo. If you have not received the update yet, please sign out and sign back in again and see if the position remains. 


@cAlgo_Fanatic

cAlgo_Fanatic
25 Apr 2013, 15:05 ( Updated at: 21 Dec 2023, 09:20 )

Unfortunately, we cannot add those buttons but you can easily use the Price DOM to make Stop Orders.


@cAlgo_Fanatic

cAlgo_Fanatic
25 Apr 2013, 14:48

Thank you for your suggestions. We will consider adding hot keys to the platform.


@cAlgo_Fanatic

cAlgo_Fanatic
24 Apr 2013, 17:57

Please reinstall cTrader and see if the problem persists. If it does please let us know and we will investigate promptly.


@cAlgo_Fanatic

cAlgo_Fanatic
24 Apr 2013, 10:23

Yes, MarketSeries.Close[MarketSeries.Close.Count - 2]; represents the second from the end close price.

MarketSeries.Close is a DataSeries which is a collection of data like an array. An array, can be thought of as a container that has a list of storage locations. These locations are accessed by their index (position). Indexing starts from zero. For example if the values contained in the MarketSeries.Close are {5,1,9} then MarketSeries.Close[0] = 5, MarketSeries.Close[1] = 1 and MarketSeries.Close[2] = 9.

MarketSeries.Close.Count is the size of the collection. In the above example it is equal to 3. So at the last location, the index is 2.
So, MarketSeries.Close.Count - 1 gives you the last index. The value at that last location is accessed like this: MarketSeries.Close.Count[MarketSeries.Close.Count - 1 ].
To make it more clear to read you can break it into two lines:

var lastIndex = MarketSeries.Close.Count - 1; 

var lastValue = MarketSeries.Close.Count[lastIndex];

To show the last 3 closing prices:

    protected override void OnTick()
    {
        var lastIndex = MarketSeries.Close.Count - 1;
        for (int i = 0; i < 3; i++)
        {
            var index = lastIndex - i;
            var price = MarketSeries.Close[index];
            Print("Closing Price at index {0} is {1}", lastIndex - i, price);
        }
    }




@cAlgo_Fanatic

cAlgo_Fanatic
24 Apr 2013, 09:30

We are already considering or working on all of your suggestions. Thank you for your input.


@cAlgo_Fanatic

cAlgo_Fanatic
24 Apr 2013, 09:22

Yes, the OnPositionOpened event is raised when a position is created. So, you can control/monitor the flow with this event.


@cAlgo_Fanatic

cAlgo_Fanatic
24 Apr 2013, 09:06

Result2[index] = double.NaN;




@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 15:09

For the time being you cannot access the Account Interface so it would not be possible to access any position of the account but there are plans to implement this.


@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 15:01

You can find the code for the momentum oscillator here: Momentum Oscillator.

 


@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 15:00

Momentum Oscillator :

using cAlgo.API;

namespace cAlgo.Indicators
{
    [Indicator("Momentum Oscillator")]
    public class MomentumOscillatorIndicator : Indicator
    {
        [Parameter]
        public DataSeries Source { get; set; }

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

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        public override void Calculate(int index)
        {
            Result[index] = 100 * Source[index] / Source[index - Periods];
        }
    }
}




@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 14:31

To hedge all positions in the Account:

        [Parameter(DefaultValue = 100000)]
        public int Volume { get; set; }

        protected override void OnStart()
        {
            foreach (var position in Account.Positions)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    Trade.CreateSellMarketOrder(Symbol, Volume);
                    //break; // optional break to hedge only one position
                }
                else
                {
                    Trade.CreateBuyMarketOrder(Symbol, Volume);
                    //break; // optional break to hedge only one position
                }
            }
        }




@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 14:14

You can set it to double.NaN for each value you want to hide.  


@cAlgo_Fanatic

cAlgo_Fanatic
23 Apr 2013, 11:34

You can reference the Keltner Channels Indicator (need to download and build) and the Bollinger Bands (build in) Indicator. The Momentum Oscillator oscillates to 100, so you would have to scale it down if you want your signal output to oscillate between 1 and 0. Also you may want to oscillate between 1 and 0.99 instead of zero so that you can see the momentum histogram properly.

//#reference: KeltnerChannels.algo
using cAlgo.API;
using cAlgo.API.Indicators;
//...

        ///////////////////////////////////////////
        // Bollinger Bands
        private BollingerBands bollingerBands;

        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType BBMaType { get; set; }
        [Parameter(DefaultValue = 2)]
        public double BBStdev { get; set; }
        [Parameter(DefaultValue = 14)]
        public int BBPeriod { get; set; }
        [Parameter]
        public DataSeries BBSource { get; set; }
        ///////////////////////////////////////////
        // Keltner Channels
        private KeltnerChannels keltnerChannels;

        [Parameter(DefaultValue = 1.5)]
        public double BandDistance { get; set; }
        [Parameter(DefaultValue = 20)]
        public int KeltnerPeriod { get; set; }

        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType KeltnerMaType { get; set; }
        
        ///////////////////////////////////////////

//...

        protected override void Initialize()
        {            
            _momentum = Indicators.MomentumOscillator(MarketSeries.Close, 14);
            bollingerBands = Indicators.BollingerBands(BBSource, BBPeriod, BBStdev, BBMaType);
            keltnerChannels = Indicators.GetIndicator<KeltnerChannels>(KeltnerPeriod, BandDistance, KeltnerMaType);            
        }
        public override void Calculate(int index)
        {

            double momentum = _momentum.Result[index];
            Result[index] = momentum/100; // scale it down

            // which is 1 when the bollinger upper band is lower than the keltner upper band, 
            // and the boll low is higher than the keltner low; otherwise the signal is 0.
            if( bollingerBands.Top[index] < keltnerChannels.ChannelUp[index] 
                && bollingerBands.Bottom[index] > keltnerChannels.ChannelLow[index])
            {
                Result2[index] = 1;
            }
            else
            {
                Result2[index] = 0.98;
            }

        }
    }
}




@cAlgo_Fanatic

cAlgo_Fanatic
22 Apr 2013, 18:10 ( Updated at: 23 Jan 2024, 13:16 )

[Today High and Low Indicator]


@cAlgo_Fanatic

cAlgo_Fanatic
22 Apr 2013, 18:01

using System ;
using cAlgo.API;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true)]
    public class TodayHighLow : Indicator
    {
        private Timeframe _timeframe = Timeframe.Na;

        private double high = double.MinValue;
        private double low = double.MaxValue;


        [Output("High", Color = Colors.Lime)]
        public IndicatorDataSeries High { get; set; }

        [Output("Low", Color = Colors.Red)]
        public IndicatorDataSeries Low { get; set; }


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

            if (_timeframe == Timeframe.Na)
            {
                _timeframe = GetTimeFrame(index);
                if (_timeframe == Timeframe.Na)
                {
                    const string naText = "Timeframe Not Applicable";
                    ChartObjects.DrawText("object1", naText, StaticPosition.TopLeft, Colors.Red);
                    return;
                }
            }

            if (_timeframe == Timeframe.D1)
            {
                High[index] = MarketSeries.High[index - 1];
                Low[index] = MarketSeries.Low[index - 1];

                return;
            }

            DateTime currentOpenTime = MarketSeries.OpenTime[index];
            bool isToday = currentOpenTime.Date == DateTime.Now.Date;

            if (isToday)
            {
                if (MarketSeries.High[index] > high)
                    high = MarketSeries.High[index];
                if (MarketSeries.Low[index] < low)
                    low = MarketSeries.Low[index];
            }

            if (IsRealTime)
            {
                for (int i = 0; i <= index; i++)
                {
                    High[i] = high;
                    Low[i] = low;
                }
            }
        }

        /// <summary>
        /// Get the current chart timeframe
        /// </summary>
        private Timeframe GetTimeFrame(int index)
        {
            DateTime currentOpenTime = MarketSeries.OpenTime[index];
            DateTime previousOpenTime = MarketSeries.OpenTime[index - 1];

            if (currentOpenTime.DayOfWeek == DayOfWeek.Monday && previousOpenTime.DayOfWeek != DayOfWeek.Monday)
            {
                currentOpenTime = previousOpenTime;
                previousOpenTime = MarketSeries.OpenTime[index - 2];
            }

            TimeSpan barTimeDiff = currentOpenTime - previousOpenTime;
            var totalMin = (int) barTimeDiff.TotalMinutes;


            switch (totalMin)
            {
                case 1:
                    return Timeframe.m1;
                case 2:
                    return Timeframe.m2;
                case 3:
                    return Timeframe.m3;
                case 4:
                    return Timeframe.m4;
                case 5:
                    return Timeframe.m5;
                case 10:
                    return Timeframe.m10;
                case 15:
                    return Timeframe.m15;
                case 30:
                    return Timeframe.m30;
                case 60:
                    return Timeframe.h1;
                case 240:
                    return Timeframe.h4;
                case 720:
                    return Timeframe.h12;
                case 1440:
                    return Timeframe.D1;
                default:
                    return Timeframe.Na;
            }
        }

        private enum Timeframe
        {
            m1,
            m2,
            m3,
            m4,
            m5,
            m10,
            m15,
            m30,
            h1,
            h4,
            h12,
            D1,
            Na
        }
    }
}

 


@cAlgo_Fanatic