One position robot

Created at 09 Aug 2017, 14:28
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
HT

HTtrader

Joined 19.07.2017

One position robot
09 Aug 2017, 14:28


Hi all,

I need a bit of help getting a parameter into my cbot. I have the trade logic working fine and it creates and opens as per the onbar function. However I want to limit this function to only open 1 trade rather than multiple trades that meet the on bar criteria. I have done some research and it looks like the onpositionopen seems logical to use.

Does anyone out there have an example I could possibly use? That either stops the onbar action or sets a trade timer before the next onbar event is allowed to happen.

Thanks to anyone who can help.


@HTtrader
Replies

Spotware
09 Aug 2017, 14:37

Dear hungtonydang,

Thanks for posting in our forum. If you just need to have one position open at a time, you can check the number of open positions before executing your logic. See a small example below

        protected override void OnBar()
        {
            if (Positions.Count == 0)
            {
                // Execute your logic here
            }
        }

Please let us know if the above is helpful for you.

Best Regards,

cTrader Team


@Spotware

HTtrader
09 Aug 2017, 15:35

Thanks for the prompt response I will try that later. 

I am after some logic that would also restrict the onbar logic to have 1 trade per wave per se which is normally after about 6 bars. 

At the moment my onbar logic opens new trades concurrently one bar after another until the logic fails. I would like to have one trade overall as the subsequent trades tend to hit sl where as the initial hit tp.

Any help is much appreciated.


@HTtrader

HTtrader
11 Aug 2017, 00:17

Ok I have an idea but just wanted thoughts on it.

If I use the above code and specify less than 1 position that should only allow the one position from opening. Then if I make an OnPositionClosed to sleep the robot for the next 12 hours, would that work? or can I use the OnPositionOpen, but then would that cancel my stop and take profit orders?

Sample below I hope I have my numbers and symbols right

protected override void OnBar()
{
    if (Positions.Count < 1)
    {
        // Execute your logic here
    }
}

protect override void OnPositionOpen()
{
int milliseconds = 120000000;
System.Threading.Thread.Sleep(milliseconds);
}

 


@HTtrader

Spotware
11 Aug 2017, 09:37

Dear hungtonydang,

Stop Loss and Take Profit are executed on the server, therefore it does not matter whether your cBot is running or not. Since your logic will not be executed when you have a position open, why do you need to stop the cBot from running? If you elaborate a bit on what you need to do, maybe somebody could propose a better way to handle this.

Best Regards,

cTrader Team


@Spotware

HTtrader
11 Aug 2017, 16:47

I am trying to get the bot to execute 1 trade every say 24 hours. So therefore I would like to pause the onbar logic from opening further positions after the first one has been closed rather than stop the whole bot as I would normally be asleep by the time the bot is running.

 


@HTtrader

Spotware
11 Aug 2017, 17:29

Hi hungtonydang,

You could try something like the following. You can record the time of the last executed order and then check if 24 hours have passed from the last order or not

        protected override void OnBar()
        {
            if (_lastExecutedOrder.AddHours(24) < DateTime.Now)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
                _lastExecutedOrder = DateTime.Now;
            }
        }

Best Regards,

cTrader Team


@Spotware

HTtrader
22 Aug 2017, 00:16

I found a bit of C# code that might be able to do what I need however it is coming up with errors once I hit the build button. Any help is much appreciated.

        protected override void OnBar()
        {
            if (true == true)
            {
                var volumeInUnits = Symbol.QuantityToVolume(Quantity);
                {
                    if (Positions.Count == 1)
                    {
                        await Task.Delay(TimeSpan.FromHours(8));
                    }

That is my sample code, it says the name Task does not exist in the current context and consider changing to async method.


@HTtrader

HTtrader
23 Aug 2017, 00:16

Ok I have this working now but it is not working as expected. I am guessing that it might have something to do with the nested if functions that open an order after the delay. 

Is there anywhere I can see some examples of nested if functions on async bots? Or does anyone have sample lines of code they could share please?

I am trying to get the market entry parameters to follow the if statement after the delay has been taken into effect but under the async operation it goes through the code and assigns new entries on the condition being false.

Any help or sample is much appreciated


@HTtrader

HTtrader
26 Aug 2017, 09:20

RE:

Spotware said:

Hi hungtonydang,

You could try something like the following. You can record the time of the last executed order and then check if 24 hours have passed from the last order or not

        protected override void OnBar()
        {
            if (_lastExecutedOrder.AddHours(24) < DateTime.Now)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
                _lastExecutedOrder = DateTime.Now;
            }
        }

Best Regards,

cTrader Team

I am trying the above code however I get the following error

Error CS0103: The name '_lastExecutedOrder' does not exist in the current context

I am guessing that _lastExecutedOrder needs to be declared as a variable before it can be used. Can anyone help me with the right syntax for the declaration.


@HTtrader

Spotware
28 Aug 2017, 10:02

Dear hungtonydang,

Yes the variable needs to be declared. See a more complete example below.

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private DateTime _lastExecutedOrder;

        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
            _lastExecutedOrder = DateTime.Now;
        }

        protected override void OnBar()
        {
            if (_lastExecutedOrder.AddHours(24) < DateTime.Now)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
                _lastExecutedOrder = DateTime.Now;
            }
        }

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

Best Regards,

cTrader Team


@Spotware

HTtrader
29 Aug 2017, 15:44

RE:

Hi ctrader team,

Just to help my understanding of the code. In the first instance of creating private function you are declaring the class to be used.

subsequently after said event you are assigning it a new variable that is passed to the class as a check value? Is that the logic?

If so could I perhaps do something like this

private DateTime _lastClosedOrder;
 
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
        }
        protected override void OnBar()
        {
            if (_lastClosedOrder.AddHours(24) < DateTime.Now)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, 1000);
            }
        }
        protected override void OnPositionClosed()
        {
                _lastClosedOrder = DateTime.Now;
            }
        }
 

Or is there some other syntax for closed position I should be using? I have looked at your references page but there was little about calling this up.


@HTtrader

Spotware
30 Aug 2017, 09:04

Hi hungtonydang,

See the below code sample demonstrating how to listen to the OnPositionsClosed event.

        protected override void OnStart()
        {            
            Positions.Closed += OnPositionsClosed;
        }

        void OnPositionsClosed(PositionClosedEventArgs obj)
        {
         
        }  

Best Regards,

cTrader Team


@Spotware

HTtrader
10 Sep 2017, 14:04

Hi ctrader team I now have a 2 part query, I have built my bot and it works perfectly for the last executed order scenario, however my adaptation of last closed order doesn't seem to be responding as favourably and I had 2 open orders. Now my question lies does the last executed order interpret the code as being the last order to enter the market or does that include pending orders as well? As this could solve my limit order dilemma. I have the cbot now placing limit orders with 1 hour expiry but am wondering if I had the clause of last executed would it still work and keep placing limit orders until 1 of the enters the market and sets the parameter?

The second part of my question comes with my other thread of multiple instances. I am currently testing this but my data set is not large and expansive enough yet to draw a conclusion. I would like to know if this last executed order would carry through to all instances of the code or would they be independent? I am taking a guess that I might have to put a if statement about symbol code in the middle somewhere, can you please confirm this. As an example I have the one cbot code running on the eurusd and gbpusd and usdyen, 1 trade gets triggered on the eurusd does that now stop the gbpusd and usdyen from working if the signal to enter is there?


@HTtrader

Spotware
11 Sep 2017, 09:46

Dear hungtonydang,

"does the last executed order interpret the code as being the last order to enter the market or does that include pending orders as well"

In order to provide an accurate answer, we will need to see your cBot's code. But most probably the answer is no since up to now you were working with Positions and not with orders.

" I would like to know if this last executed order would carry through to all instances of the code or would they be independent"

Yes it will. If you need to separate positions between different instances, you are advised to use the label parameter when executing an order.

Best Regards,

cTrader Team


@Spotware

HTtrader
14 Sep 2017, 00:07

Hi Ctrader team,

Please see the code below

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
using System.Threading.Tasks;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.TasmaniaStandardTime, AccessRights = AccessRights.None)]
    public class HunterBB : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 40, MinValue = 1)]
        public int StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 40, MinValue = 1)]
        public int TakeProfitInPips { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Cooldown (hours)", DefaultValue = 2, MinValue = 1, Step = 1)]
        public double CD { get; set; }

        [Parameter("Bollinger Bands Deviations", DefaultValue = 2)]
        public double Deviations { get; set; }

        [Parameter("Bollinger Bands Periods", DefaultValue = 20)]
        public int Periods { get; set; }

        [Parameter("Bollinger Bands MA Type")]
        public MovingAverageType MAType { get; set; }

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

        public Position position;
        private DateTime _lastExecutedOrder;

        BollingerBands BB;


        protected override void OnStart()
        {
            BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType);
        }

        protected override void OnBar()
        {

            var midbb = BB.Main.Last(0);
            var topnow = BB.Top.Last(0);
            var bottomnow = BB.Bottom.Last(0);

            var volumeInUnits = Symbol.QuantityToVolume(Quantity);
            var expiry = Time.AddHours(1);


            if (_lastExecutedOrder.AddHours(CD) < DateTime.Now)
            {
                //higher than indicator target price
                PlaceLimitOrder(TradeType.Sell, Symbol, volumeInUnits, topnow + 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
                //lower than indicator target price
                PlaceLimitOrder(TradeType.Buy, Symbol, volumeInUnits, bottomnow - 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
                _lastExecutedOrder = DateTime.Now;
            }

            foreach (var position in Positions)
            {
                if (Symbol.Code == position.SymbolCode)
                {
                    ModifyPositionAsync(position, position.StopLoss, midbb);
                    Print("New Position TP price is {0}", position.TakeProfit);
                }
            }
        }

        protected override void OnStop()
        {
            Stop();
        }
    }
}

I am trying to get this work to across multiple instances, do I need to bind the symbol such as put

_lastExecutedOrder.Symbol.Code = DateTime.Now;

I have done some preliminary testing and the results of which tell me that the last executed order does include pending orders, Is there a way to modify it to being open orders? As my last closed order didn't work.


@HTtrader

Spotware
14 Sep 2017, 09:17

Dear hungtonydang,

If you wish to set the _lastExecutedOrder only whenever an order is executed, you should apply the following changes to your code.

First of all you need to an event handler for the Positions.Opened event as follows
 

        protected override void OnStart()
        {
            BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType);
            Positions.Opened += OnPositionsOpened;
        }

Then in the event handler you can set the _lastExecutedOrder. See below

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            _lastExecutedOrder = DateTime.Now;
        }

See the full modified code below

 

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
using System.Threading.Tasks;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.TasmaniaStandardTime, AccessRights = AccessRights.None)]
    public class HunterBB : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 40, MinValue = 1)]
        public int StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 40, MinValue = 1)]
        public int TakeProfitInPips { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Cooldown (hours)", DefaultValue = 2, MinValue = 1, Step = 1)]
        public double CD { get; set; }

        [Parameter("Bollinger Bands Deviations", DefaultValue = 2)]
        public double Deviations { get; set; }

        [Parameter("Bollinger Bands Periods", DefaultValue = 20)]
        public int Periods { get; set; }

        [Parameter("Bollinger Bands MA Type")]
        public MovingAverageType MAType { get; set; }

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

        public Position position;
        private DateTime _lastExecutedOrder;

        BollingerBands BB;


        protected override void OnStart()
        {
            BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType);
            Positions.Opened += OnPositionsOpened;
        }

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            _lastExecutedOrder = DateTime.Now;
        }

        protected override void OnBar()
        {

            var midbb = BB.Main.Last(0);
            var topnow = BB.Top.Last(0);
            var bottomnow = BB.Bottom.Last(0);

            var volumeInUnits = Symbol.QuantityToVolume(Quantity);
            var expiry = Time.AddHours(1);


            if (_lastExecutedOrder.AddHours(CD) < DateTime.Now)
            {
                //higher than indicator target price
                PlaceLimitOrder(TradeType.Sell, Symbol, volumeInUnits, topnow + 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
                //lower than indicator target price
                PlaceLimitOrder(TradeType.Buy, Symbol, volumeInUnits, bottomnow - 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
            }

            foreach (var position in Positions)
            {
                if (Symbol.Code == position.SymbolCode)
                {
                    ModifyPositionAsync(position, position.StopLoss, midbb);
                    Print("New Position TP price is {0}", position.TakeProfit);
                }
            }
        }

        protected override void OnStop()
        {
            Stop();
        }
    }
}

Let us know if this is what you are looking for.

Best Regards,

cTrader Team


@Spotware

HTtrader
14 Sep 2017, 11:02

Thanks ctrader team,

I understand how the code should work and hopefully it does as it suppose to. I will test it out later tonight. My only concern now is would this work across multiple instances like the same code being used for eurusd and gbpusd for example. If 1 trade gets opened does that trigger the event for all other instances? That where I was wondering if I had to bind it to the symbol or position id I have made a parameter for. Unfortunately this cannot be back tested so I am only going off the live information I have gathered so far.

 


@HTtrader

Spotware
14 Sep 2017, 11:28

Hi hungtonydang,

If you wish your code in the event handler to be executed only for the selected symbol, you can modify it as follows

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            if (Symbol.Code == obj.Position.SymbolCode)
            {
                _lastExecutedOrder = DateTime.Now;
            }
        }

Best Regards,

cTrader Team


@Spotware

jani
07 Nov 2019, 15:40

RE:

Spotware said:

Dear hungtonydang,

If you wish to set the _lastExecutedOrder only whenever an order is executed, you should apply the following changes to your code.

First of all you need to an event handler for the Positions.Opened event as follows
 

        protected override void OnStart()
        {
            BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType);
            Positions.Opened += OnPositionsOpened;
        }

Then in the event handler you can set the _lastExecutedOrder. See below

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            _lastExecutedOrder = DateTime.Now;
        }

See the full modified code below

 

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
using System.Threading.Tasks;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.TasmaniaStandardTime, AccessRights = AccessRights.None)]
    public class HunterBB : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 40, MinValue = 1)]
        public int StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 40, MinValue = 1)]
        public int TakeProfitInPips { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Cooldown (hours)", DefaultValue = 2, MinValue = 1, Step = 1)]
        public double CD { get; set; }

        [Parameter("Bollinger Bands Deviations", DefaultValue = 2)]
        public double Deviations { get; set; }

        [Parameter("Bollinger Bands Periods", DefaultValue = 20)]
        public int Periods { get; set; }

        [Parameter("Bollinger Bands MA Type")]
        public MovingAverageType MAType { get; set; }

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

        public Position position;
        private DateTime _lastExecutedOrder;

        BollingerBands BB;


        protected override void OnStart()
        {
            BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType);
            Positions.Opened += OnPositionsOpened;
        }

        void OnPositionsOpened(PositionOpenedEventArgs obj)
        {
            _lastExecutedOrder = DateTime.Now;
        }

        protected override void OnBar()
        {

            var midbb = BB.Main.Last(0);
            var topnow = BB.Top.Last(0);
            var bottomnow = BB.Bottom.Last(0);

            var volumeInUnits = Symbol.QuantityToVolume(Quantity);
            var expiry = Time.AddHours(1);


            if (_lastExecutedOrder.AddHours(CD) < DateTime.Now)
            {
                //higher than indicator target price
                PlaceLimitOrder(TradeType.Sell, Symbol, volumeInUnits, topnow + 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
                //lower than indicator target price
                PlaceLimitOrder(TradeType.Buy, Symbol, volumeInUnits, bottomnow - 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry);
            }

            foreach (var position in Positions)
            {
                if (Symbol.Code == position.SymbolCode)
                {
                    ModifyPositionAsync(position, position.StopLoss, midbb);
                    Print("New Position TP price is {0}", position.TakeProfit);
                }
            }
        }

        protected override void OnStop()
        {
            Stop();
        }
    }
}

Let us know if this is what you are looking for.

Best Regards,

cTrader Team

Problem with this code is that it is not working in backtesting as DateTime.Now give current computer time not the server time backtesting is reading.

if (_lastExecutedOrder.AddHours(CD) < DateTime.Now)

I would never run any cBot live before I have backtested it.... But thanks for your effort. I'll try to look if I can find a solution

 


@jani

PanagiotisCharalampous
07 Nov 2019, 15:42

Hi Jan,

If you need the server time you can use Server.Time.

Best Regards,

Panagiotis


@PanagiotisCharalampous