One way trend Sell - SmartGrid MA LimitStop Sell trend. For Gold sell trend. What are your ideas for improving the code after testing?

Created at 01 Oct 2019, 21:30
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!
TG

tgjobscv

Joined 05.12.2018

One way trend Sell - SmartGrid MA LimitStop Sell trend. For Gold sell trend. What are your ideas for improving the code after testing?
01 Oct 2019, 21:30


Hi.

Mod SmartGrid:

https://ctrader.com/algos/cbots/show/876

up 07.2020

SellSmartGrid - Only - Sell trend (parametr Buy is ignoring) with MA and one way trend LimitStop Sell H1 H4 - only Sell trend backtest date.

using System;
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 oSGMASell : Robot
    {
        private bool _accountIsOutOfMoney;
        private int _openTradeResult;

        private readonly string Label = "SmartPSell";
        private DateTime _lastBuyTradeTime;
        private DateTime _lastSellTradeTime;

        [Parameter("Source SMA_AO")]
        public DataSeries Source_SMA { get; set; }


        [Parameter("Buy", DefaultValue = false)]
        public bool Buy { get; set; }

        [Parameter("Sell", DefaultValue = true)]
        public bool Sell { get; set; }

        [Parameter("Pip Step", DefaultValue = 10, MinValue = 5)]
        public int PipStep { get; set; }

        [Parameter("First Volume", DefaultValue = 10, MinValue = 10, Step = 10)]
        public int FirstVolume { get; set; }

        [Parameter("Volume Exponent", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)]
        public double VolumeExponent { get; set; }

        [Parameter("Max Spread", DefaultValue = 3.0)]
        public double MaxSpread { get; set; }

        [Parameter("Average TP", DefaultValue = 300, MinValue = 10)]
        public int AverageTakeProfit { get; set; }

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




        private double CurrentSpread
        {
            get { return (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; }
        }

        private SimpleMovingAverage _SMA_slow;
        private SimpleMovingAverage _SMA_Fast;

        protected override void OnStart()
        {
        }

        protected override void OnTick()
        {
            _SMA_slow = Indicators.SimpleMovingAverage(Source_SMA, 200);
            _SMA_Fast = Indicators.SimpleMovingAverage(Source_SMA, 50);


            if (_SMA_slow.Result.LastValue > _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue > Symbol.Bid)
            {
                Buy = false;
                Sell = true;
                ChartObjects.DrawText("Sell", ("Vender"), StaticPosition.TopLeft, Colors.AliceBlue);
            }
            if (_SMA_slow.Result.LastValue < _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue < Symbol.Ask)
            {
                Buy = false;
                Sell = true;
                ChartObjects.DrawText("buy", ("Comprar"), StaticPosition.TopLeft, Colors.AliceBlue);
            }

            if (CountOfTradesOfType(TradeType.Buy) > 0)
                AdjustBuyPositionTakeProfits(CalculateAveragePositionPrice(TradeType.Buy), AverageTakeProfit);
            if (CountOfTradesOfType(TradeType.Sell) > 0)
                AdjustSellPositionTakeProfits(CalculateAveragePositionPrice(TradeType.Sell), AverageTakeProfit);
            if (CurrentSpread <= MaxSpread && !_accountIsOutOfMoney)
                ProcessTrades();

            if (!this.IsBacktesting)
                DisplayStatusOnChart();
        }

        protected override void OnError(Error error)
        {
            if (error.Code == ErrorCode.NoMoney)
            {
                _accountIsOutOfMoney = true;
                Print("opening stopped because: not enough money");
            }
        }

        protected override void OnBar()
        {
            RefreshData();
        }

        protected override void OnStop()
        {
            ChartObjects.RemoveAllObjects();
        }

        private void ProcessTrades()
        {

            if (Buy && CountOfTradesOfType(TradeType.Buy) == 0 && MarketSeries.Close.Last(1) > MarketSeries.Close.Last(2))
            {
                _openTradeResult = OrderSend(TradeType.Buy, LimitVolume(FirstVolume));
                if (_openTradeResult > 0)
                    _lastBuyTradeTime = MarketSeries.OpenTime.Last(0);
                else
                    Print("First BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
            }
            if (Sell && CountOfTradesOfType(TradeType.Sell) == 0 && MarketSeries.Close.Last(2) > MarketSeries.Close.Last(1))
            {
                _openTradeResult = OrderSend(TradeType.Sell, LimitVolume(FirstVolume));
                if (_openTradeResult > 0)
                    _lastSellTradeTime = MarketSeries.OpenTime.Last(0);
                else
                    Print("First SELL opening error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
            }

            if (CountOfTradesOfType(TradeType.Buy) > 0)
            {
                if (Math.Round(Symbol.Ask, Symbol.Digits) < Math.Round(FindLowestPositionPrice(TradeType.Buy) - PipStep * Symbol.PipSize, Symbol.Digits) && _lastBuyTradeTime != MarketSeries.OpenTime.Last(0))
                {
                    var calculatedVolume = CalculateVolume(TradeType.Buy);
                    _openTradeResult = OrderSend(TradeType.Buy, LimitVolume(calculatedVolume));
                    if (_openTradeResult > 0)
                        _lastBuyTradeTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("Next BUY opening error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
                }
            }
            if (CountOfTradesOfType(TradeType.Sell) > 0)
            {
                if (Math.Round(Symbol.Bid, Symbol.Digits) > Math.Round(FindHighestPositionPrice(TradeType.Sell) + PipStep * Symbol.PipSize, Symbol.Digits) && _lastSellTradeTime != MarketSeries.OpenTime.Last(0))
                {
                    var calculatedVolume = CalculateVolume(TradeType.Sell);
                    _openTradeResult = OrderSend(TradeType.Sell, LimitVolume(calculatedVolume));
                    if (_openTradeResult > 0)
                        _lastSellTradeTime = MarketSeries.OpenTime.Last(0);
                    else
                        Print("Next SELL opening error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
                }
            }
        }



        private int OrderSend(TradeType tradeType, long volumeToUse)
        {
            var returnResult = 0;
            if (volumeToUse > 0)
            {
                var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, StopLoss, 0, 0, "smart_grid");

                if (result.IsSuccessful)
                {
                    Print(tradeType, "Opened at: ", result.Position.EntryPrice, result.Position.StopLoss);
                    returnResult = 1;
                }
                else
                    Print(tradeType, "Openning Error: ", result.Error);
            }
            else
                Print("Volume calculation error: Calculated Volume is: ", volumeToUse);
            return returnResult;
        }
        private void AdjustBuyPositionTakeProfits(double averageBuyPositionPrice, int averageTakeProfit)
        {
            foreach (var buyPosition in Positions)
            {
                if (buyPosition.Label == Label && buyPosition.SymbolCode == Symbol.Code)
                {
                    if (buyPosition.TradeType == TradeType.Buy)
                    {
                        double? calculatedTakeProfit = Math.Round(averageBuyPositionPrice + averageTakeProfit * Symbol.PipSize, Symbol.Digits);
                        if (buyPosition.TakeProfit != calculatedTakeProfit)
                            ModifyPosition(buyPosition, buyPosition.StopLoss, calculatedTakeProfit);
                    }
                }
            }
        }

        private void AdjustSellPositionTakeProfits(double averageSellPositionPrice, int averageTakeProfit)
        {
            foreach (var sellPosition in Positions)
            {
                if (sellPosition.Label == Label && sellPosition.SymbolCode == Symbol.Code)
                {
                    if (sellPosition.TradeType == TradeType.Sell)
                    {
                        double? calculatedTakeProfit = Math.Round(averageSellPositionPrice - averageTakeProfit * Symbol.PipSize, Symbol.Digits);
                        if (sellPosition.TakeProfit != calculatedTakeProfit)
                            ModifyPosition(sellPosition, sellPosition.StopLoss, calculatedTakeProfit);
                    }
                }
            }
        }

        private void DisplayStatusOnChart()
        {
            if (CountOfTradesOfType(TradeType.Buy) > 1)
            {
                var y = CalculateAveragePositionPrice(TradeType.Buy);
                ChartObjects.DrawHorizontalLine("bpoint", y, Colors.Yellow, 2, LineStyle.Dots);
            }
            else
                ChartObjects.RemoveObject("bpoint");
            if (CountOfTradesOfType(TradeType.Sell) > 1)
            {
                var z = CalculateAveragePositionPrice(TradeType.Sell);
                ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
            }
            else
                ChartObjects.RemoveObject("spoint");
            ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.Tomato);
        }

        private string GenerateStatusText()
        {
            var statusText = "";
            var buyPositions = "";
            var sellPositions = "";
            var spread = "";
            var buyDistance = "";
            var sellDistance = "";
            spread = "\nSpread = " + Math.Round(CurrentSpread, 1);
            buyPositions = "\nBuy Positions = " + CountOfTradesOfType(TradeType.Buy);
            sellPositions = "\nSell Positions = " + CountOfTradesOfType(TradeType.Sell);
            if (CountOfTradesOfType(TradeType.Buy) > 0)
            {
                var averageBuyFromCurrent = Math.Round((CalculateAveragePositionPrice(TradeType.Buy) - Symbol.Bid) / Symbol.PipSize, 1);
                buyDistance = "\nBuy Target Away = " + averageBuyFromCurrent;
            }
            if (CountOfTradesOfType(TradeType.Sell) > 0)
            {
                var averageSellFromCurrent = Math.Round((Symbol.Ask - CalculateAveragePositionPrice(TradeType.Sell)) / Symbol.PipSize, 1);
                sellDistance = "\nSell Target Away = " + averageSellFromCurrent;
            }
            if (CurrentSpread > MaxSpread)
                statusText = "MAX SPREAD EXCEED";
            else
                statusText = "Smart Grid" + buyPositions + spread + sellPositions + buyDistance + sellDistance;
            return (statusText);
        }



        private int CountOfTradesOfType(TradeType tradeType)
        {
            var tradeCount = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                        tradeCount++;
                }
            }

            return tradeCount;
        }

        private double CalculateAveragePositionPrice(TradeType tradeType)
        {
            double result = 0;
            double averagePrice = 0;
            long count = 0;


            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                    {
                        averagePrice += position.EntryPrice * position.Volume;
                        count += position.Volume;
                    }
                }

            }

            if (averagePrice > 0 && count > 0)
                result = Math.Round(averagePrice / count, Symbol.Digits);
            return result;
        }

        private double FindLowestPositionPrice(TradeType tradeType)
        {
            double lowestPrice = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                    {
                        if (lowestPrice == 0)
                        {
                            lowestPrice = position.EntryPrice;
                            continue;
                        }
                        if (position.EntryPrice < lowestPrice)
                            lowestPrice = position.EntryPrice;
                    }
                }
            }

            return lowestPrice;
        }

        private double FindHighestPositionPrice(TradeType tradeType)
        {
            double highestPrice = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                    {
                        if (highestPrice == 0)
                        {
                            highestPrice = position.EntryPrice;
                            continue;
                        }
                        if (position.EntryPrice > highestPrice)
                            highestPrice = position.EntryPrice;
                    }
                }
            }

            return highestPrice;
        }

        private double FindPriceOfMostRecentPositionId(TradeType tradeType)
        {
            double price = 0;
            var highestPositionId = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                    {
                        if (highestPositionId == 0 || highestPositionId > position.Id)
                        {
                            price = position.EntryPrice;
                            highestPositionId = position.Id;
                        }
                    }
                }
            }

            return price;
        }

        private long GetMostRecentPositionVolume(TradeType tradeType)
        {
            long mostRecentVolume = 0;
            var highestPositionId = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType)
                    {
                        if (highestPositionId == 0 || highestPositionId > position.Id)
                        {
                            mostRecentVolume = position.Volume;
                            highestPositionId = position.Id;
                        }
                    }
                }
            }

            return mostRecentVolume;
        }

        private int CountNumberOfPositionsOfType(TradeType tradeType)
        {
            var mostRecentPrice = FindPriceOfMostRecentPositionId(tradeType);
            var numberOfPositionsOfType = 0;

            foreach (var position in Positions)
            {
                if (position.Label == Label && position.SymbolCode == Symbol.Code)
                {
                    if (position.TradeType == tradeType && tradeType == TradeType.Buy)
                    {
                        if (Math.Round(position.EntryPrice, Symbol.Digits) <= Math.Round(mostRecentPrice, Symbol.Digits))
                            numberOfPositionsOfType++;
                    }
                    if (position.TradeType == tradeType && tradeType == TradeType.Sell)
                    {
                        if (Math.Round(position.EntryPrice, Symbol.Digits) >= Math.Round(mostRecentPrice, Symbol.Digits))
                            numberOfPositionsOfType++;
                    }
                }
            }

            return (numberOfPositionsOfType);
        }

        private long CalculateVolume(TradeType tradeType)
        {
            var numberOfPositions = CountNumberOfPositionsOfType(tradeType);
            var mostRecentVolume = GetMostRecentPositionVolume(tradeType);
            var calculatedVolume = Symbol.NormalizeVolume(mostRecentVolume * Math.Pow(VolumeExponent, numberOfPositions));
            return (calculatedVolume);
        }

        private long LimitVolume(long volumeIn)
        {
            var symbolVolumeMin = Symbol.VolumeMin;
            var symbolVolumeMax = Symbol.VolumeMax;
            var result = volumeIn;
            if (result < symbolVolumeMin)
                result = symbolVolumeMin;
            if (result > symbolVolumeMax)
                result = symbolVolumeMax;
            return (result);
        }
    }
}

 

up 07.2020

What are your ideas for improving the code after testing - for Sell trend in xauusd, xagusd, majors etc ?

SellSmartGrid - improving ?!

How 1. cTrader demo to live ctrader, mt4/mt5 Trade Copier ?

How 2. mt4/mt5 demo to live ctrader, mt4/mt5 Trade Copier ?


@tgjobscv
Replies

tgjobscv
01 Oct 2019, 21:44

How limit max sell position in code ?
[Parameter("Maximum open Sell position?", DefaultValue = 5, MinValue = 0)]
        public int MaxOpenSell { get; set; }

Code for library.

How put limit max sell position in code ?


@tgjobscv

tgjobscv
17 Oct 2019, 22:51

How change for stop orders ?

Now open sell limit orders.

How mod for sell stop orders ?

 


@tgjobscv

PanagiotisCharalampous
18 Oct 2019, 08:14

Hi tgjobscv,

You can access all your orders via PendingOrders and modify them accodingly. See example below

 PendingOrders[0].ModifyVolume(1000);

Best Regards,

Panagiotis


@PanagiotisCharalampous

Mr4x
23 Nov 2019, 06:41

Great Concept, a few bugs

Hi tgjobscv,

Your code works a treat when selling XAUUSD over the past 3 months of this year, however if you try to do a back-test on a $10,000 account over the past year (22-11-18 to 22-11-19) you do get 100% draw-down during December 2018. Might need to tweak the code a bit?

Anyway the feature that is broken is the ability to use this as "buy only". If you set "buy" to yes and "sell" to no then try and back-test, the cbot still places sell side orders. I'm looking at running a hedge-type situation using a buy with XAUEUR side-by-side with sell XAUUSD, so if you could fix the cbot and then maybe play around with that idea of mine too and see what you think.

Cheers,

Mr4x


@Mr4x

tgjobscv
26 Jul 2020, 17:56

RE: Great Concept, a few bugs

Mr4x said:

Hi tgjobscv,

Your code works a treat when selling XAUUSD over the past 3 months of this year, however if you try to do a back-test on a $10,000 account over the past year (22-11-18 to 22-11-19) you do get 100% draw-down during December 2018. Might need to tweak the code a bit?

Anyway the feature that is broken is the ability to use this as "buy only". If you set "buy" to yes and "sell" to no then try and back-test, the cbot still places sell side orders. I'm looking at running a hedge-type situation using a buy with XAUEUR side-by-side with sell XAUUSD, so if you could fix the cbot and then maybe play around with that idea of mine too and see what you think.

Cheers,

Mr4x

up 07.2020

SellSmartGrid - Only - Sell trend (parametr Buy is ignoring) with MA and one way trend LimitStop Sell H1 H4 - only Sell trend backtest date.

 

What are your ideas for improving the code after testing - for Sell trend in xauusd, xagusd, majors etc ?

SellSmartGrid - improving ?!

 

How 1. cTrader demo to live ctrader, mt4/mt5 Trade Copier ?

How 2. mt4/mt5 demo to live ctrader, mt4/mt5 Trade Copier ?


@tgjobscv