Untitled

 avatar
unknown
plain_text
2 months ago
17 kB
5
Indexable
using System;
using System.ComponentModel;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.FullAccess, AddIndicators = true, TimeZone = TimeZones.EasternStandardTime)]
    public class ScalpingUtec : Robot
    {

        [Parameter("Hour End", Group = "Box", DefaultValue = 9)]
        public int HourEnd { get; set; }

        [Parameter("Minute End", Group = "Box", DefaultValue = 29)]
        public int MinuteEnd { get; set; }

        [Parameter("CHour End", Group = "Destroy Limit", DefaultValue = 9)]
        public int CLimitHourEnd { get; set; }

        [Parameter("RHour End", Group = "Destroy Limit", DefaultValue = 10)]
        public int RLimitHourEnd { get; set; }

        [Parameter("RMinute End", Group = "Destroy Limit", DefaultValue = 30)]
        public int RLimitMinuteEnd { get; set; }
        
        [Parameter("Hour End", Group = "Destroy Position", DefaultValue = 19)]
        public int PositionHourEnd { get; set; }

        [Parameter("Minute End", Group = "Destroy Position", DefaultValue = 00)]
        public int PositionMinuteEnd { get; set; }

        [Parameter("Hour End", Group = "Ending Session", DefaultValue = 10)]
        public int SessionHourEnd { get; set; }

        [Parameter("Minute End", Group = "Ending Session", DefaultValue = 29)]
        public int SessionMinuteEnd { get; set; }

        [Parameter("Look Back Bars", Group = "Box", DefaultValue = 89)]
        public int BoxLookBackBars { get; set; }

        [Parameter("Breaker After Cont Bars", Group = "Box", DefaultValue = 2)]
        public int breakerAfterBoxBars { get; set; }

        [Parameter("Breaker After Reve Bars", Group = "Box", DefaultValue = 21)]
        public int breakerAfterBoxReversalBars { get; set; }


        [Parameter("RR", Group = "Risk", DefaultValue = 2)]
        public double RR { get; set; }

        [Parameter("SL Gap", Group = "Risk", DefaultValue = 50)]
        public double stoplossPipsGap { get; set; }

        [Parameter("Risk percent", Group = "Risk", DefaultValue = 1)]
        public double riskPercent { get; set; }

        [Parameter("Apply Balance", Group = "Risk", DefaultValue = 3000)]
        public double applyBalance { get; set; }

        [Parameter("Max Limit State", Group = "Risk", DefaultValue = 4)]
        public double maxLimitState { get; set; }

        [Parameter("Max Position State", Group = "Risk", DefaultValue = 2)]
        public double maxPositionState { get; set; }


        // PRIVATE
        private double boxHigh, boxLow;

        private bool isBoxForming = false;
        private bool isRunSearching = false;
        private bool isKillSession = false;
        private string breakerSide = "none";
        private string caseBias = "none";

        private double EntryPrice, StoplossPips;

        //private int _breakerAfterBoxBarsCount = 0;

        private int _positionOpenedCount = 0;
        private int[] _minutesBreakerContinue = { 30, 31 };
        private int[] _minutesBreakerReversal = { 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 };

        protected override void OnStart()
        {
            boxHigh = double.MinValue; boxLow = double.MaxValue;

            Positions.Opened += OnPositionOpened;
        }

        private void OnPositionOpened(PositionOpenedEventArgs args)
        {
            Print("What Opened");
            _positionOpenedCount++;
        }

        protected override void OnBar()
        {
            // Handle price updates here
            DateTime lastBarTime = Bars.OpenTimes.Last(1);

            Chart.DrawStaticText(
                "dashboard_minix",
                $"-- Now {lastBarTime.Hour}:{lastBarTime.Minute} \n" +
                $"-- Position items {_positionOpenedCount} \n" +
                $"-- Limit items {PendingOrders.Where(pod => pod.SymbolName == Symbol.Name).Count()} \n" +
                ($"-- Box High {boxHigh} | Low {boxLow} \n") +
                $"-- Break Side {breakerSide} \n" +
                $"-- case Bias {caseBias} \n" +
                $"-- Goodbye Folk ? {isKillSession} \n"
                ,
                VerticalAlignment.Bottom,
                HorizontalAlignment.Left,
                API.Color.OrangeRed
            );

            // --- Start Game Preprocessing ---
            if (_positionOpenedCount >= maxPositionState)
            {
                // Destroy all pending
                isKillSession = true;
                deleteAllPendingOrders();
            }

            // 10:00 AM - No finding new trade for Continuous
            if (caseBias == "Continue")
            {
                if ((lastBarTime.Hour > CLimitHourEnd) || (lastBarTime.Hour == SessionHourEnd && lastBarTime.Minute >= SessionMinuteEnd))
                {
                    // Destroy all pending
                    isKillSession = true;
                    deleteAllPendingOrders();
                    // caseBias | breakerSide | boxHigh |boxLow | isBoxForming -- khởi tạo mình gán nó value gì thì giờ mình gõ lại value đấy! a test kĩ lại giúp nha, có thể e sai!

                    isBoxForming = false;
                    isRunSearching = false;
                    isKillSession = true;
                    breakerSide = "none";
                    caseBias = "none";
                    boxHigh = double.MinValue; 
                    boxLow = double.MaxValue;
                    _positionOpenedCount = 0;
                }
            }
            // 10:30 AM No finding new trade for Reversal
            if (caseBias == "Reversal") 
            {
                if (((lastBarTime.Hour == RLimitHourEnd) && (lastBarTime.Minute >= RLimitMinuteEnd)) || (lastBarTime.Hour == SessionHourEnd && lastBarTime.Minute >= SessionMinuteEnd))
                {
                     // Destroy all pending
                    isKillSession = true;
                    deleteAllPendingOrders();
                    // caseBias | breakerSide | boxHigh |boxLow | isBoxForming -- khởi tạo mình gán nó value gì thì giờ mình gõ lại value đấy! a test kĩ lại giúp nha, có thể e sai!

                    isBoxForming = false;
                    isRunSearching = false;
                    isKillSession = true;
                    breakerSide = "none";
                    caseBias = "none";
                    boxHigh = double.MinValue; 
                    boxLow = double.MaxValue;
                    _positionOpenedCount = 0;
                }
            }
            if ((caseBias == "none") && ((lastBarTime.Hour == PositionHourEnd ) && (lastBarTime.Minute >= PositionMinuteEnd)))
            {
                // Destroy all pending
                isKillSession = true;
                deleteAllPendingOrders();
                // caseBias | breakerSide | boxHigh |boxLow | isBoxForming -- khởi tạo mình gán nó value gì thì giờ mình gõ lại value đấy! a test kĩ lại giúp nha, có thể e sai!
                isBoxForming = false;
                isRunSearching = false;
                isKillSession = true;
                breakerSide = "none";
                caseBias = "none";
                boxHigh = double.MinValue; 
                boxLow = double.MaxValue;
                _positionOpenedCount = 0;
            }
            // Kill Postition at 19:00
            if(lastBarTime.Hour == PositionHourEnd && lastBarTime.Minute == PositionMinuteEnd) {
                closeAllPositions();
            }
            
            // --- End Game Preprocessing ---



            // Game Start Here  
            // =================== LET GO ===================

            // Wait Box Forming - finding box at 9.30 (now is 9.30) Bars.OpenTime.Last(1) = 9.30 | Bars.OpenTime.Last(2) = 9.29
            if (lastBarTime.Hour == HourEnd && lastBarTime.Minute == MinuteEnd + 1)
            {
                isKillSession = false;
                for (int i = 2; i <= BoxLookBackBars + 1; i++)
                {
                    boxHigh = Math.Max(boxHigh, Bars.HighPrices.Last(i));
                    boxLow = Math.Min(boxLow, Bars.LowPrices.Last(i));
                }
                isBoxForming = true;
            }


            // Bars.OpenTime.Last(1) = 9.30 | 9.31 with breakerAfterBoxBars = 2
            // Wait for Breaker box -- Case Continue 
            // _breakerAfterBoxBarsCount = 0 -->  [1,2]

            // Case Continue thì mô tả xuôi checkvar 30 31 tại phút Last(1) = 30
            if (isBoxForming && _minutesBreakerContinue.Contains(lastBarTime.Minute) && lastBarTime.Hour == 9)
            {

                if (Bars.HighPrices.Last(1) > boxHigh && breakerSide == "none")
                {
                    breakerSide = "top";
                    isRunSearching = true;
                }

                if (Bars.LowPrices.Last(1) < boxLow && breakerSide == "none")
                {
                    breakerSide = "bottom";
                    isRunSearching = true;
                }

                if (isRunSearching)
                {
                    caseBias = "Continue";
                }

            }



            if (isBoxForming && breakerSide == "none")
            {
                // 9.29 (29 + 21bars = 50) | Heyyy now is 9.51 ; Last(1) = 9.51
                if (lastBarTime.Hour == HourEnd && lastBarTime.Minute == 51) // Phut 51
                {
                    // look back to 9.50 --> 9.32 (range 19 bars) , break or not ?
                    for (int i = 2; i <= 20; i++)
                    {
                        if (Bars.HighPrices.Last(i) > boxHigh)
                        {
                            breakerSide = "top";
                            isRunSearching = true;
                        }

                        if (Bars.LowPrices.Last(i) < boxLow)
                        {
                            breakerSide = "bottom";
                            isRunSearching = true;
                        }
                    }

                    if (isRunSearching)
                    {
                        caseBias = "Reversal";
                    }
                }
            }

            if (isKillSession)
            {
                return;
            }

            if (!isRunSearching) return;

            if (!this.IsImFvgBuy() && !this.IsImFvgSell()) { return; }

            if (caseBias == "Continue")
            {
                if (breakerSide == "top" && this.IsImFvgBuy())
                {
                    // Bias BUY
                    EntryPrice = Math.Min(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1)) + 3;
                    StoplossPips = convertToPips(Math.Abs(EntryPrice - Bars.LowPrices.Last(3))) + stoplossPipsGap;
                    double lots = this.getRiskLots(StoplossPips, this.riskPercent);
                    PlaceLimitOrder(
                        TradeType.Buy,
                        SymbolName,
                        Symbol.QuantityToVolumeInUnits(lots),
                        EntryPrice,
                        "continue-buy-" + Bars.Count,
                        StoplossPips,
                        StoplossPips * RR
                    );

                    Print(" --- --- BUY LIMIT --- --- ");
                }

                if (breakerSide == "bottom" && this.IsImFvgSell())
                {
                    EntryPrice = Math.Max(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1)) - 3;
                    StoplossPips = convertToPips(Math.Abs(EntryPrice - Bars.HighPrices.Last(3))) + stoplossPipsGap;
                    double lots = this.getRiskLots(StoplossPips, this.riskPercent);
                    PlaceLimitOrder(
                        TradeType.Sell,
                        SymbolName,
                        Symbol.QuantityToVolumeInUnits(lots),
                        EntryPrice,
                        "continue-sell-" + Bars.Count,
                        StoplossPips,
                        StoplossPips * RR
                    );
                    Print(" --- --- SELL LIMIT --- --- ");
                }
            }

            if (caseBias == "Reversal")
            {
                if (breakerSide == "bottom" && this.IsImFvgBuy())
                {
                    // Bias BUY
                    EntryPrice = Math.Min(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1)) + 3;
                    StoplossPips = convertToPips(Math.Abs(EntryPrice - Bars.LowPrices.Last(3))) + stoplossPipsGap;
                    double lots = this.getRiskLots(StoplossPips, this.riskPercent);
                    PlaceLimitOrder(
                        TradeType.Buy,
                        SymbolName,
                        Symbol.QuantityToVolumeInUnits(lots),
                        EntryPrice,
                        "reversal-buy-" + Bars.Count,
                        StoplossPips,
                        StoplossPips * RR
                    );

                    Print(" --- --- BUY LIMIT --- --- ");
                }

                if (breakerSide == "top" && this.IsImFvgSell())
                {
                    EntryPrice = Math.Max(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1)) - 3;
                    StoplossPips = convertToPips(Math.Abs(EntryPrice - Bars.HighPrices.Last(3))) + stoplossPipsGap;
                    double lots = this.getRiskLots(StoplossPips, this.riskPercent);
                    PlaceLimitOrder(
                        TradeType.Sell,
                        SymbolName,
                        Symbol.QuantityToVolumeInUnits(lots),
                        EntryPrice,
                        "reversal-sell-" + Bars.Count,
                        StoplossPips,
                        StoplossPips * RR
                    );
                    Print(" --- --- SELL LIMIT --- --- ");
                }
            }
            if (caseBias == "none")
            {
                return;
            }
        }

        protected override void OnTick()
        {


        }

        protected override void OnStop()
        {
            // Handle cBot stop here
        }
        private double getRiskLots(double stopLossPips = 20, double riskPercentage = 1)
        {
            return Symbol.VolumeInUnitsToQuantity(Symbol.NormalizeVolumeInUnits(
                    this.getRiskCash(riskPercentage) / (stopLossPips * Symbol.PipValue)
            ));
        }
        private double getRiskCash(double riskPercentage)
        {
            return riskPercentage * 0.01 * this.getBalance();
        }
        private double getBalance()
        {

            return this.applyBalance;
        }
        private void deleteAllPendingOrders()
        {

            // Loop through each pending order and delete it

            foreach (var pod in PendingOrders.Where(pod => pod.SymbolName == Symbol.Name))
            {
                CancelPendingOrder(pod);
            }
        }
        
        private void closeAllPositions()
        {
            Print("** closeAllPositions");
            foreach (var pos in Positions.Where(pos => pos.SymbolName == Symbol.Name))
            {
                ClosePositionAsync(pos);
            }
        }


        private bool IsImFvgBuy()
        {

            bool check1 = Bars.LowPrices.Last(1) > Math.Max(Bars.OpenPrices.Last(3), Bars.ClosePrices.Last(3));
            bool check2 = Bars.HighPrices.Last(3) < Math.Min(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1));
            return check1 && check2;

        }

        private bool IsImFvgSell()
        {
            bool check1 = Bars.HighPrices.Last(1) < Math.Min(Bars.OpenPrices.Last(3), Bars.ClosePrices.Last(3));
            bool check2 = Bars.HighPrices.Last(3) > Math.Max(Bars.OpenPrices.Last(1), Bars.ClosePrices.Last(1));

            return check1 && check2;

        }

        private double convertToPips(double priceDif)
        {
            return Math.Round(Math.Abs(priceDif / Symbol.PipSize), 1);
        }


    }
}
Leave a Comment