Topics
Replies

firemyst
05 Mar 2024, 07:54

RE: RE: Run code Once Per new bar

mihlali700 said: 

firemyst said: 

It's not running on every tick; it's running every bar. The index you're printing confirms it.

When you first load a chart in cTrader, it loads previous bars, and runs through the calculations on those, and that's exactly what's happening here, unless it gets to the latest bar.

Sort the log by the date/time DESCENDING instead of ASCENDING and you'll see with the most recent data it only executes once per bar.

So its going through the entire index once per bar ? 
What if I just want data from the latest index and only starting from that index ? Like I want to print the value of the indicator but only for the latest bar 

No, it's not going through all the indexes once per bar. As I said, when you first start cTrader, it loads up all the previous bars because it has to. Otherwise,e there's no way to display previous chart data is there?

If you only want data from the latest index going forward, then in your Initialize method, get the latest index:

int latestIndex = Bars.OpenTimes.Count - 1

Then in your calculate method check if index ≥ latestIndex before doing anything.


@firemyst

firemyst
05 Mar 2024, 03:11 ( Updated at: 05 Mar 2024, 06:44 )

It's not running on every tick; it's running every bar. The index you're printing confirms it.

When you first load a chart in cTrader, it loads previous bars, and runs through the calculations on those, and that's exactly what's happening here, unless it gets to the latest bar.

Sort the log by the date/time DESCENDING instead of ASCENDING and you'll see with the most recent data it only executes once per bar.


@firemyst

firemyst
05 Mar 2024, 03:06 ( Updated at: 05 Mar 2024, 06:44 )

RE: RE: RE: Is it better to call the indicator or write the indicator yourself?

PanagiotisCharalampous said: 

 

In principle no, as long as the implementations are identical. However, since there are always specifics in each case, this needs to be checked on a case by case basis.

Out of curiosity, are the native built in cTrader indicators written in .Net as well? Or another language like C++


@firemyst

firemyst
05 Mar 2024, 03:00 ( Updated at: 05 Mar 2024, 06:44 )

foreach (Position p in Positions)
{
    if (p.SymbolName == "whatever symbol you want to close")
        ClosePosition(p);
}

@firemyst

firemyst
05 Mar 2024, 02:57 ( Updated at: 05 Mar 2024, 06:44 )

Try reading Spotware's documentation and Google:

https://help.ctrader.com/ctrader-automate/compiling/#parameters

 

 


@firemyst

firemyst
03 Mar 2024, 03:30

RE: Is it better to call the indicator or write the indicator yourself?

PanagiotisCharalampous said: 

Hi there,

Unfortunately I cannot understand the question and I guess many other readers. Could you please rephrase and provide some examples of what you are doing?

Best regards,

Panagiotis

I think what the OP is asking is if he's writing either a bot or a custom indicator that references a common indicator like the EMA, does the code execute faster if he references the native indicator in cTrader, or codes his own EMA within the custom indicator/bot he's writing. 

Since nano-seconds can make a difference, he's essentially wonder if anyone's done any bench marks to see which way is faster.

That's how I read it.


@firemyst

firemyst
25 Feb 2024, 12:39

RE: RE: Historical Data for Range charts

roan.is said: 

firemyst said: 

This is probably dependent on your broker. 

Why not open your cTrader, put on a big range like 100 pips per bar, and see how far back it goes?

Thanks for your reply.  Unfortunately, I don't have access to cTrader at the moment (no computer), hence my question. But I'll certainly do a check as soon as I can. 

When you change bar sizes, just keep scrolling left to bring in more historical data. See how far the rabbit hole goes.


@firemyst

firemyst
25 Feb 2024, 12:23

This is probably dependent on your broker. 

Why not open your cTrader, put on a big range like 100 pips per bar, and see how far back it goes?


@firemyst

firemyst
22 Feb 2024, 02:24 ( Updated at: 22 Feb 2024, 07:46 )

Duplicate. Original one is here:

https://ctrader.com/forum/cbot-support/42928

 


@firemyst

firemyst
21 Feb 2024, 11:45

RE: Protect orders/positions against manual modifications

ncel01 said: 

Unintentional manual modifications.

Semantics. Unintentional by you or someone else. Either way, with how the charts are structured and the location of controls, it takes a lot to do something ‘unintentional’ while looking at the charts with a position you're in – someone has to physically move, point, and click a mouse button, especially if you've removed all the hot key shortcuts. That's a lot for being unintentional while trading on a live account.

And besides moving the SL/TP, I don't know what else you could easily reverse/reset if something ‘unintentional’ is done.

 


@firemyst

firemyst
21 Feb 2024, 08:30

RE: RE: Protect orders/positions against manual modifications

ncel01 said: 

firemyst said: 

Yes it can. You'll have to implement checks. There's no way currently to prevent a user from manually modify an order (SL/TP), but you can always keep track of the last value your bot moved it too and then revert back to those values if they were updated.

 

Other modifications like increasing/decreasing the position size and such will be a bit more tricky because you'll first have to start by asking yourself… if someone manually decreased your position size, would you really want to increase it back to where it was?

 

That's exactly about check and revert as I mentioned above.

I think the most effective way was to have an option on cTrader settings for the active account. 

Allow manual trading for the account? Y/N

In addition, this would also save all the effort to code an (not so effective) alternative.

The first question to possibly ask is if you're trading via automation, who would be adjusting the trades manually? If it's not you, and you're running the bots, then maybe the easiest approach would just be to ask whoever else has access to actually not trade anything. 


@firemyst

firemyst
21 Feb 2024, 01:38

RE: RE: Amount to trade depending on stop loss

oliver.r.m.92 said: 

 

I have rewritten the code and used your part of code but now I have a new problem, in the log it shows this message: Crashed in OnBar with ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: volume. Actual value was: NaN.

The new code:

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.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MACDcBot : Robot
    {
        private bool isPositionOpen;
        private MacdCrossOver _MACD;
        private MovingAverage EMA;
        private const string label = "Trade ON";
        private double stopLossPrice;

        //MA                
        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }

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

        [Parameter("MA Periods", Group = "Moving Average", DefaultValue = 200)]
        public int MAPeriods { get; set; }

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

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal-line crossover true:if Signal-line crossover false: Zero crossover", DefaultValue = true)]
        public bool IsSignalLineCrossover { get; set; }

        protected override void OnStart()
        {
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            EMA = Indicators.MovingAverage(SourceSeries, MAPeriods, MAType);
            isPositionOpen = false;
            Positions.Closed += OnPositionsClosed;
        }

        protected override void OnBar()
        {           
            if (Positions.Count > 0)
            {
                var position = Positions.LastOrDefault();

                if (position != null)
                {
                    if (position.TradeType == TradeType.Buy)
                        stopLossPrice = EMA.Result.LastValue - Symbol.PipSize * 2; // 2 pips por debajo de la SMA de 200
                    else if (position.TradeType == TradeType.Sell)
                        stopLossPrice = EMA.Result.LastValue + Symbol.PipSize * 2; // 2 pips por encima de la SMA de 200

                    double takeProfitPrice = position.EntryPrice + (position.EntryPrice - stopLossPrice) * 1.5;

                    ModifyPosition(position, stopLossPrice, takeProfitPrice);
                }
            }

            // Calcula el tamaño de posición basado en el riesgo
            var maxAmountRisked = Account.Equity * (1 / 100);
            var positionSize = Symbol.NormalizeVolumeInUnits(maxAmountRisked / (stopLossPrice * Symbol.PipValue), RoundingMode.Down);
            
            if (IsSignalLineCrossover)
            {
                if (!isPositionOpen && _MACD.Histogram.LastValue > 0 && _MACD.Signal.LastValue < 0 && _MACD.MACD.Last(3) < _MACD.Signal.Last(3) && _MACD.MACD.Last(2) > _MACD.Signal.Last(2) && Bars.HighPrices.Last(1) > EMA.Result.Last(3))
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, positionSize, label);
                    isPositionOpen = true;
                }

                if (!isPositionOpen && _MACD.Histogram.LastValue < 0 && _MACD.Signal.LastValue > 0 && _MACD.MACD.Last(3) > _MACD.Signal.Last(3) && _MACD.MACD.Last(2) < _MACD.Signal.Last(2) && Bars.LowPrices.Last(1) < EMA.Result.Last(3))
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, positionSize, label);
                    isPositionOpen = true;
                }
            }
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            isPositionOpen = false;
        }
    }
}

 

Of course it throws an error. Look at your code in OnBar.

Look at the code you ALWAYS execute regardless if you're in a position or not. 

Where do you set stopLossPrice (I bolded it in the code above) if you don't have any positions? You're trying to do a calculation using it when you're not setting it.

 

I also suggest you starting learning how to use Print statements in your code to print values to the log. THen if you put print statements everywhere, you also know where your code is crashing.

 


@firemyst

firemyst
21 Feb 2024, 01:25

I don't understand what you're saying. Read that sentence outloud to yourself, especially the italics part:

“You can see here although in the code the close of bar 2 should be greater than or equal to the open of bar 3 but in this pic its tell yet the Bot still took the trade .”
 

In the screen capture you provided, the close of 2 bars back is greater than the close of the 3rd bar back from the current bar.


@firemyst

firemyst
21 Feb 2024, 01:16

Yes it can. You'll have to implement checks. There's no way currently to prevent a user from manually modify an order (SL/TP), but you can always keep track of the last value your bot moved it too and then revert back to those values if they were updated.

 

Other modifications like increasing/decreasing the position size and such will be a bit more tricky because you'll first have to start by asking yourself… if someone manually decreased your position size, would you really want to increase it back to where it was?

 


@firemyst

firemyst
15 Feb 2024, 03:53

I'm not sure how you could account for that? Would be interesting to know if it can be done.

For instance, do you know what the lag time will be between the time your bot places an order, when the server receives your order, and when it's actually executed? 

You could be doing a replay at a time when the market is closed, or very slow, and thus little lag; whereas when you run your bot it may be during peak trading hours and could be lots of internet congestion.


@firemyst

firemyst
13 Feb 2024, 01:02

Just choose to export your history as an Excel file and then save that file as a CSV.


@firemyst

firemyst
13 Feb 2024, 00:46

#1 you an already do. Just go to the update order screen and reduce the number of lots/units you have, and/or set a smart “take profit” level. 


@firemyst

firemyst
13 Feb 2024, 00:39 ( Updated at: 13 Feb 2024, 00:44 )

Are you able to provide screen captures of your back-test parameters?

 

Also, I don't believe async trade operations are fully supported in backtest or work as expected in backtest by their very nature… eg, in backtest mode, everything is “instantaneous” as opposed to live markets where one async call may execute right away, others will have a delay, etc etc.


@firemyst

firemyst
13 Feb 2024, 00:36

What time frame are you using?

You don't say, and that's what's causing your issue. 

 

Obviously that will make a difference. Your default lookback period is 1000. So if you're on a weekly, daily, 4-hourly, 200 Renko, 100-range, 2/3/4 hour HA, etc etc, you won't have more bars than your lookback period, so your “else” logic never gets executed.

 if (index < LookbackPeriod)
    {
        RenkoTop[index] = double.NaN;
        RenkoBottom[index] = double.NaN;
        CurrentBrick[index] = double.NaN;
        return;
    }
    
    			// HOW DO YOU EXPECT THIS LOGIC TO EVER BE EXECUTED
    			// with a 1000 lookback period when you
    			//have less than 1000 (default lookback period) bars on the chart?
    			//Unless you get more than 1000 bars/candles on a chart, index
    			//will always be less than the lookback period except in 1 case.
    			
     double atrValue = _atr.Result[index];
    _brickSize = atrValue;

if (index == LookbackPeriod)
    {
        RenkoTop[index] = Bars.ClosePrices[index];
        RenkoBottom[index] = Bars.ClosePrices[index] - _brickSize;
        _isAscending = Bars.ClosePrices[index] > Bars.ClosePrices[index - 1];
    }
    else
    {

    }

 

You should debug your code by putting in lots of print statements to see where it's getting to, and what parts of your logic are or are not being executed.

 


@firemyst

firemyst
11 Feb 2024, 12:32

You know the candle's closing time because it's almost exactly the next candle's open time regardless of the time frame or chart you use - a new candle won't open unless the previous candle has closed.


@firemyst