Replies

Drummond360
22 Jan 2018, 22:31

Sorry, may have jumped the gun posting about this.... So I have got some positive value statements in my Log... 

I'm guessing the interbank spread is negative fairly often? and as I'm using an ECN broker and paying trade commisions I get the interbank spread?

Right?!?


@Drummond360

Drummond360
22 Jan 2018, 18:13

Hi All,

When back testing you need to make sure you are using tick data from server.. If you use minute bars you are only getting the open price to test with... This can be the difference between millions in profit and a blown account...

Also in your account images above you have 178 open positions! if you are trailing stops or doing anything onTick then latency could be a big issue!

Happy trading...


@Drummond360

Drummond360
20 Jan 2018, 22:29 ( Updated at: 21 Dec 2023, 09:20 )

I'm having these results too, along with some other issues... My cBot is turning £10K into over £1 million in 21 days but only if I set the backtesting dates 5 months apart, if I set the dates 21 dates apart it makes around £400K... 

Might this have anything to do with the white results in the trade history?

 


@Drummond360

Drummond360
17 Jan 2018, 17:03

RE:

Spotware said:

You can set a boolean field in the OnPositionClosed method and then check if you can open positions.

Set the boolean field:

         private bool isOpenPositionsPermitted;

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

        void OnPositionsClosed(PositionClosedEventArgs args)
        {
            isOpenPositionsPermitted = false;
        }

Check if the position is closed in the OnTick/OnBar events or your user defined method which opens positions:

if(isOpenPositionsPermitted)
{
  // Your logic to open positions
}

Reset the boolean field to false according to your algorithm logic. If you want to count 10 bars then set a variable in the  OnPositionsClosed to the bar count:

        private int barCountSinceLastPosition;

        void OnPositionsClosed(PositionClosedEventArgs args)
        {
            isOpenPositionsPermitted = false;
            barCountSinceLastPosition = MarketSeries.Close.Count;
        }

Check if the bar count value against the current bar in the OnTick/OnBar events or your user defined method which opens positions:

if (MarketSeries.Close.Count - barCountSinceLastPosition >= 10)
{
    isOpenPositionspermitted = true;
}

 

Typo in last line: 'isOpenPositionspermitted' should be 'isOpenPositionsPermitted'... Had me confused for a wee while so thought I'd share...


@Drummond360

Drummond360
12 Jan 2018, 10:59

That's great thank you Panagiotis..

Can I email you all this information?

 


@Drummond360

Drummond360
11 Jan 2018, 18:50

Might it be easier to 'toggle a bool' if an order is found?

 

var longPosition = Positions.Find(label, Symbol, TradeType.Buy);

bool longO = false;
            
            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy && order.Label == label && order.SymbolCode == Symbol.Code)
                {
                    longO = true;
                }
            }

            if (longPosition == null && longO == false)
            
            {
                PlaceStopOrder

 


@Drummond360

Drummond360
11 Jan 2018, 16:15 ( Updated at: 21 Dec 2023, 09:20 )

A better image incase you can't see it...


@Drummond360

Drummond360
11 Jan 2018, 14:36

Yes it is absolultey flawed as it uses only the open price...

If you have a trailing stop of 5 pips and the next candle open is 20 pips away (from previous open), then the price action reverses to meet the SL... In a 1 min backtest the result will assume your stop has had a nice smooth trail and register a profit of 15 pips...

If you run the same backtest with Tick data it will likley post a loss as the spot price darts around the candles highs and lows hitting stops along the way...

There's no point in trying to code this out.. When trading live we are at the mercy of the bid and ask levels, we can't ask our brokers to only respect the close or open prices... 

Is there really any need for other options in backtesting? We should all be testing with tick data, with acurate interbank spreads and every tick registering if it hits our stops or entries...

I really hope I'm wrong about all this but I fear I'm not!

 


@Drummond360

Drummond360
11 Jan 2018, 13:44

Sorry ignore my last post, I've just discovered backtesting with tick data to offer more exact results...

 


@Drummond360

Drummond360
11 Jan 2018, 10:51

Hi Panagiotis,

Thank you for the quick reply... After thinking a little more on this I doubt it will fix my problem anyway...

I want my robot to check the spread so that it can provide more realistic backtest results...

However, I now assume that the backtest data is only the Bid price in order to draw the charts, then the user specifies the spread in the backtest parameters which then calculates the ask price... Is this correct?

If so, is there any 'best practice' to mimic realistic spreads in backtesting...

I'm using cAlgo with FxPro which offers the Interbank spread without a markup...

Thanks again for your help,

Drummond360


@Drummond360

Drummond360
10 Jan 2018, 22:11

RE:

Spotware said:

var averageSpreadFromPreviousWeek = Math.Round(Symbol.Spread[ average from previous week ] / Symbol.PipSize, 2);

Historical tick data is not available in cAlgo.API. However there is a workaround to retrieve it. You can backtest your cBot in tick data mode and perform all required calculations based on historical Bid and Ask prices.

 

Hi,

Is this answer still relevant?

I'm getting a print statement that doesnt make sense! and it the spread remains this value with every print, it never changes!

03/01/2018 13:25:00.000 |  spread = 9.9999999999989E-05

 

Using this code:

             double _Spread = Symbol.Ask - Symbol.Bid;
            Print(" spread = " + _Spread);

Am I missing something?!??!


@Drummond360

Drummond360
05 Jan 2018, 12:37

Yep all good now, thank you for confirming...


@Drummond360

Drummond360
04 Jan 2018, 20:18

Could you please explain why you use PipValue to calculate the trailing stop distance instead of PipSize?

var newSLprice = Symbol.Ask - (Symbol.PipValue * TrailingStopLossDistance);

I've implemented this but am getting the error TRADING_BAD_STOPS


@Drummond360

Drummond360
04 Jan 2018, 17:03

Thank you Panagiotis...

Yes I did think about that conflict. The code is from one of the sample snippets on this forum..

After deleting that if statement it seems to be working, I'll keep testing...

Thanks again...

 


@Drummond360

Drummond360
04 Jan 2018, 16:40

Thank you Panagiotis, here's the code

 

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

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

        [Parameter("Pips Away", DefaultValue = 1, MinValue = 1)]
        public int PipsAway { get; set; }

        [Parameter("Initial Pips Away", DefaultValue = 1, MinValue = 1)]
        public int InitialPipsAway { get; set; }

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

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

        //[Parameter("Volume", DefaultValue = 10000, MinValue = 1000)]
        //public int Volume { get; set; }


        [Parameter("Order Duration", DefaultValue = 5, MinValue = 1)]
        public int Duration { get; set; }

        [Parameter("Risk % on A/C: 1 = 1 mini lot on £10K", DefaultValue = 1, MinValue = 0.1, MaxValue = 100)]
        public double risk { get; set; }


        [Parameter("Trailing Stop Loss Distance", DefaultValue = 10)]
        public double TrailingStopLossDistance { get; set; }

        public int Count { get; set; }

        Dictionary<int, int> dic = new Dictionary<int, int>();
        string label = "Scalper";

        protected override void OnStart()
        {


        }
        private void ExecuteOrder(int volume, TradeType tradeType)
        {
            ExecuteMarketOrder(tradeType, Symbol, volume, label, StopLoss, TakeProfit);
        }
        protected override void OnTick()
        {
            var longPosition = Positions.Find(label, Symbol, TradeType.Buy);
            var shortPosition = Positions.Find(label, Symbol, TradeType.Sell);
            var totalOrders = PendingOrders.Count;
            var sellOrderTargetPrice = Symbol.Bid - InitialPipsAway * Symbol.PipSize;
            var buyOrderTargetPrice = Symbol.Ask + InitialPipsAway * Symbol.PipSize;
            var smartVolume = Symbol.NormalizeVolume(risk * Account.Balance, RoundingMode.Down);


            if (shortPosition == null && totalOrders < 1)
            {
                PlaceStopOrder(TradeType.Sell, Symbol, smartVolume, sellOrderTargetPrice, label, StopLoss, TakeProfit, Server.Time.AddMinutes(Duration));

            }

            if (longPosition == null && totalOrders < 1)
            {
                PlaceStopOrder(TradeType.Buy, Symbol, smartVolume, buyOrderTargetPrice, label, StopLoss, TakeProfit, Server.Time.AddMinutes(Duration));

            }


            // Once orders are placed they trail the spot price by 1 pip awaitng the price reversal
            foreach (var order in PendingOrders)
            {
                var targetPrice = (order.TradeType == TradeType.Buy) ? Symbol.Ask - PipsAway * Symbol.PipSize : Symbol.Bid + PipsAway * Symbol.PipSize;

                if (order.StopLossPips == null)

                    ModifyPendingOrder(order, targetPrice, order.StopLoss, order.TakeProfit, Server.Time.AddMinutes(Duration));
                Print("MODIFYING PENDING ORDER target price is " + order.TargetPrice + " targetPrice Variable result =  " + targetPrice + " ...order ID = " + order.Id + " ...Pips away Value = " + PipsAway + " ...PipsAway*SymbolPipsize = " + PipsAway * Symbol.PipSize);
            }

            // Once a position is open it is indexed to be managed individually
            var symbolSearch = Positions.FindAll(label, Symbol);

            int posCount = Positions.Count;

            foreach (Position position in symbolSearch)

                for (int y = posCount - 1; y >= 0; y--)
                {
                    int totalPips = (int)(Positions[y].Pips);

                    int test = 0;
                    if (!dic.TryGetValue(Positions[y].Id, out test))
                    {
                        dic[Positions[y].Id] = 0;
                    }

                    //If a position enters a profit of 1 pip or more then start trailing the stop loss
                    if (totalPips >= 0.001)

                        //Based on the position's direction, we calculate the new stop loss price and we modify the position
                        // Using Symbol.PipSize instead of Symbol.PipValue seems the correct logic but is less profitable! What calculation is actually happening here?!?!

                        if (Positions[y].TradeType == TradeType.Buy)
                        {
                            var newSLprice = Symbol.Ask - (Symbol.PipValue * TrailingStopLossDistance);
                            if (newSLprice > Positions[y].StopLoss)
                            {
                                ModifyPosition(Positions[y], newSLprice, null);
                            }
                        }
                        else
                        {
                            var newSLprice = Symbol.Bid + (Symbol.PipValue * TrailingStopLossDistance);
                            if (newSLprice < Positions[y].StopLoss)
                            {
                                ModifyPosition(Positions[y], newSLprice, null);

                            }
                        }
                }
        }
    }
}






 


@Drummond360

Drummond360
04 Jan 2018, 14:12

This code isn't working, can you please advise on my mistake?

Is it possible to make the order.TargetPrice respect the variable targetPrice?

    foreach (var order in PendingOrders)
            {
                var targetPrice = (order.TradeType == TradeType.Buy) ? Symbol.Ask + PipsAway * Symbol.PipSize : Symbol.Bid - PipsAway * Symbol.PipSize;

                if (order.StopLossPips == null)

                    ModifyPendingOrder(order, targetPrice, order.StopLoss, order.TakeProfit, Server.Time.AddMinutes(Duration));
                Print("MODIFYING PENDING ORDER target price is " + order.TargetPrice + " targetPrice Variable result =  " + targetPrice + " order ID = " + order.Id);
            }

Any help would be greatley appreciated...


@Drummond360

Drummond360
04 Jan 2018, 11:13

Thank you for your quick reply....

I'm limiting my cBot to just 1 long and 1 short order per instance. Might this Boolean aproach work?

bool longPendingorder = false;

foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy && order.Label == label && order.SymbolCode == Symbol.Code)
                {
                    longPendingorder = true;
                }
            }

Then I can place a long order if longPendingorder == false......?

My apologies if this is nonsesnse! As mentioned in my other posts I'm a novice with code...

 


@Drummond360

Drummond360
03 Jan 2018, 15:30

Thank you for commenting....

After running this live yesterday I'm working on restricting how active it is...

It's now much smoother and only allows 2 positions to be open at once...

I'll crack on with de-bugging and share the code when it's a little less embaracing!!

 


@Drummond360

Drummond360
02 Jan 2018, 13:57 ( Updated at: 21 Dec 2023, 09:20 )

Here's a shorter test with stats:

 


@Drummond360

Drummond360
30 Dec 2017, 15:35

That's great thank you very much for your time... : )


@Drummond360