Untitled
unknown
plain_text
a year ago
13 kB
6
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