Untitled

 avatar
unknown
plain_text
5 months ago
13 kB
5
Indexable
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using System;
using System.Collections.Generic;
using System.Linq;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EditedSeconbars_addbox : Robot
    {
        #region Parameters
        [Parameter("Holdings ", DefaultValue = 5)]
        public int PosHoldings { get; set; }
        
        [Parameter("Risk/Reward Ratio", DefaultValue = 3)]
        public double RR { get; set; }
        
        [Parameter("Max Balance Risk", DefaultValue = 10000)]
        public int MaxBalanceRisk { get; set; } 
        
        [Parameter("Cancel Pending After (bars)", DefaultValue = 15)]
        public int CancelPendingAfter { get; set; } 
        
        [Parameter("Min SL Pips", DefaultValue = 5)]
        public double MinSlPips { get; set; }
        
        [Parameter("Risk Percentage", DefaultValue = 1)]
        public double RiskBase { get; set; }

        [Parameter("Box Start Hour (UTC)", DefaultValue = 19)]
        public int StartHour { get; set; }

        [Parameter("Box End Hour (UTC)", DefaultValue = 5)]
        public int EndHour { get; set; }

        [Parameter("New York Offset", Group = "Trading Hours", DefaultValue = -5)]
        public int NyOffset { get; set; }

        [Parameter("Trading Start Hour (NY)", Group = "Trading Hours", DefaultValue = 9)]
        public int HourFrom { get; set; }

        [Parameter("Trading End Hour (NY)", Group = "Trading Hours", DefaultValue = 12)]
        public int HourTo { get; set; }
        #endregion

        #region Private Fields
        private double todayBoxHigh = double.MinValue;
        private double todayBoxLow = double.MaxValue;
        private bool isBuyDay;
        private bool isSellDay;
        private bool goLimit;
        private TradeType? currentTradeType;
        private double entryPrice;
        private double stopLossPrice;
        private readonly Dictionary<string, int> barsSinceOrderCreation = new Dictionary<string, int>();
        private DateTime lastTradingDay;
        private DateTime boxEndTime;
        #endregion

        protected override void OnStart()
        {
            lastTradingDay = Server.Time.AddDays(-1);
            ValidateParameters();
        }

        private void ValidateParameters()
        {
            if (RR <= 0) throw new ArgumentException("Risk/Reward ratio must be positive");
            if (MinSlPips <= 0) throw new ArgumentException("Minimum stop loss pips must be positive");
            if (RiskBase <= 0 || RiskBase > 100) throw new ArgumentException("Risk percentage must be between 0 and 100");
            if (PosHoldings <= 0) throw new ArgumentException("Holdings must be positive");
        }

        private void DailySetup()
        {
            try
            {
                DateTime serverTime = Server.Time;
                DateTime nyStart = serverTime.AddHours(NyOffset).Date.AddHours(StartHour);
                DateTime nyEnd = serverTime.AddHours(NyOffset).Date.AddHours(EndHour);
                
                if (nyEnd < nyStart)
                {
                    nyEnd = nyEnd.AddDays(1);
                }

                boxEndTime = nyEnd;
                isBuyDay = false;
                isSellDay = false;

                CalculateBoxBoundaries(nyStart, nyEnd);
                DrawBox("TodayBox", nyStart, todayBoxLow, nyEnd, todayBoxHigh, Color.Blue);
            }
            catch (Exception ex)
            {
                Print($"Error in DailySetup: {ex.Message}");
            }
        }

        private void CalculateBoxBoundaries(DateTime start, DateTime end)
        {
            todayBoxHigh = double.MinValue;
            todayBoxLow = double.MaxValue;

            for (int i = 0; i < MarketSeries.Close.Count; i++)
            {
                DateTime barTime = MarketSeries.OpenTime[i];
                if (barTime >= start && barTime <= end)
                {
                    double closePrice = MarketSeries.Close[i];
                    todayBoxHigh = Math.Max(todayBoxHigh, closePrice);
                    todayBoxLow = Math.Min(todayBoxLow, closePrice);
                }
            }
        }

        private void CheckBoxBreak()
        {
            if (Server.Time >= boxEndTime)
            {
                double currentPrice = MarketSeries.Close.Last(0);
                
                if (!isBuyDay && !isSellDay)  // Only check if no signal set yet
                {
                    if (currentPrice > todayBoxHigh)
                    {
                        isSellDay = true;
                        Print($"Set as SELL day - Price {currentPrice} crossed above box high {todayBoxHigh}");
                    }
                    else if (currentPrice < todayBoxLow)
                    {
                        isBuyDay = true;
                        Print($"Set as BUY day - Price {currentPrice} crossed below box low {todayBoxLow}");
                    }
                }
            }
        }

        protected override void OnBar()
        {
            try
            {
                if (IsNewTradingDay())
                {
                    DailySetup();
                    CleanupOldOrders();
                }

                CheckBoxBreak();
                
                var currentHour = Server.Time.AddHours(NyOffset).Hour;
                ProcessPendingOrders();
                UpdateTradeSignals();
                
                goLimit = currentHour >= HourFrom && currentHour <= HourTo;

                UpdateDashboard(currentHour);

                if (CanPlaceNewOrders())
                {
                    ExecuteTradeStrategy();
                }
            }
            catch (Exception ex)
            {
                Print($"Error in OnBar: {ex.Message}");
            }
        }

        private void ProcessPendingOrders()
        {
            foreach (var label in barsSinceOrderCreation.Keys.ToList())
            {
                if (!barsSinceOrderCreation.ContainsKey(label)) continue;

                barsSinceOrderCreation[label]++;

                if (barsSinceOrderCreation[label] >= CancelPendingAfter)
                {
                    PendingOrder pod = PendingOrders.FirstOrDefault(order => 
                        order.Label == label && order.SymbolName == Symbol.Name);
                    pod?.Cancel();
                }
            }
        }

        private void UpdateTradeSignals()
        {
            if (IsBuyModel())
            {
                currentTradeType = TradeType.Buy;
                entryPrice = Bars.LowPrices.Last(1);
                stopLossPrice = Bars.LowPrices.Last(2);
                DrawSignalLines("buy");
            }
            else if (IsSellModel())
            {
                currentTradeType = TradeType.Sell;
                entryPrice = Bars.HighPrices.Last(1);
                stopLossPrice = Bars.HighPrices.Last(2);
                DrawSignalLines("sell");
            }
        }

        private void DrawSignalLines(string type)
        {
            if (type == "buy")
            {
                Chart.DrawHorizontalLine("gap-top", Bars.LowPrices.Last(1), Color.DarkRed);
                Chart.DrawHorizontalLine("gap-bottom", Bars.HighPrices.Last(3), Color.DarkRed);
            }
            else
            {
                Chart.DrawHorizontalLine("gap-bottom", Bars.HighPrices.Last(1), Color.DarkRed);
                Chart.DrawHorizontalLine("gap-top", Bars.LowPrices.Last(3), Color.DarkRed);
            }
        }

        private void DrawBox(string name, DateTime start, double low, DateTime end, double high, Color color)
        {
            var boxObject = Chart.DrawRectangle(name, start, low, end, high, color, 1, LineStyle.Solid);
            boxObject.IsFilled = true;
        }

        private bool CanPlaceNewOrders()
        {
            return countExecutingPositions() + countPendingOrders() < PosHoldings 
                   && (IsBuyModel() || IsSellModel()) 
                   && goLimit;
        }

        private void ExecuteTradeStrategy()
        {
            if (currentTradeType == TradeType.Buy)
            {
                PlaceBuyOrder();
            }
            else if (currentTradeType == TradeType.Sell)
            {
                PlaceSellOrder();
            }
        }

        private void PlaceBuyOrder()
        {
            double stoplossPip = CalculateStopLossPips(entryPrice, stopLossPrice);
            double lots = CalculateLotSize(stoplossPip);
            
            string orderLabel = $"order-buy-{Bars.Count}";
            PlaceLimitOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(lots),
                entryPrice, orderLabel, stoplossPip, stoplossPip * RR);
                
            barsSinceOrderCreation[orderLabel] = 0;
        }

        private void PlaceSellOrder()
        {
            double stoplossPip = CalculateStopLossPips(entryPrice, stopLossPrice);
            double lots = CalculateLotSize(stoplossPip);
            
            string orderLabel = $"order-sell-{Bars.Count}";
            PlaceLimitOrder(TradeType.Sell, SymbolName, Symbol.QuantityToVolumeInUnits(lots),
                entryPrice, orderLabel, stoplossPip, stoplossPip * RR);
                
            barsSinceOrderCreation[orderLabel] = 0;
        }

        private double CalculateStopLossPips(double entry, double stopLoss)
        {
            return Math.Max(convertToPips(Math.Abs(entry - stopLoss)), MinSlPips);
        }

        private double CalculateLotSize(double stopLossPips)
        {
            return getRiskLots(stopLossPips, RiskBase);
        }

        private void UpdateDashboard(int currentHour)
        {
            Chart.DrawStaticText(
                "dashboard_minix",
                $"Model: {currentTradeType}\n" +
                $"Current Hour (NY): {currentHour}\n" +
                $"Trading Allowed: {goLimit}\n" +
                $"Box High: {todayBoxHigh:F5}\n" +
                $"Box Low: {todayBoxLow:F5}\n" +
                $"Is Buy Day: {isBuyDay}\n" +
                $"Is Sell Day: {isSellDay}",
                VerticalAlignment.Bottom,
                HorizontalAlignment.Left,
                Color.GreenYellow
            );
        }

        private bool IsBuyModel()
        {
            return (Bars.LowPrices.Last(1) > Bars.HighPrices.Last(3)) && isBuyDay;
        }

        private bool IsSellModel()
        {
            return (Bars.HighPrices.Last(1) < Bars.LowPrices.Last(3)) && isSellDay;
        }

        private double getRiskLots(double stopLossPips, double riskPercentage)
        {
            if (stopLossPips <= 0) throw new ArgumentException("Stop loss pips must be positive");
            double riskAmount = getRiskCash(riskPercentage);
            return Symbol.VolumeInUnitsToQuantity(Symbol.NormalizeVolumeInUnits(
                riskAmount / (stopLossPips * Symbol.PipValue)
            ));
        }

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

        private double getRiskCash(double riskPercentage)
        {
            return Math.Min(Account.Balance, MaxBalanceRisk) * (riskPercentage / 100);
        }

        private int countPendingOrders()
        {
            return PendingOrders.Count(pod => Symbol.Name == pod.SymbolName);
        }

        private int countExecutingPositions()
        {
            return Positions.Count(position =>
                (position.TradeType == TradeType.Buy || position.TradeType == TradeType.Sell)
                && Symbol.Name == position.SymbolName);
        }

        private void CleanupOldOrders()
        {
            var activeLabels = PendingOrders
                .Where(o => o.SymbolName == Symbol.Name)
                .Select(o => o.Label)
                .ToList();
                
            foreach (var label in barsSinceOrderCreation.Keys.ToList())
            {
                if (!activeLabels.Contains(label))
                {
                    barsSinceOrderCreation.Remove(label);
                }
            }
        }

        private bool IsNewTradingDay()
        {
            DateTime currentServerTime = Server.Time;
            if (currentServerTime.Date != lastTradingDay.Date)
            {
                lastTradingDay = currentServerTime;
                return true;
            }
            return false;
        }
    }
}
Editor is loading...
Leave a Comment