Untitled
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