could you help me about my code errors?

Created at 18 Sep 2024, 15:12
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!
CH

chenshy27

Joined 06.05.2024

could you help me about my code errors?
18 Sep 2024, 15:12


using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using System;
using System.Collections.Generic;

namespace cAlgo.Robots
{
   [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
   public class ThreePairsTradeBot : Robot
   {
       private Symbol gbpjpySymbol, gbpusdSymbol, usdjpySymbol;
       private RelativeStrengthIndex gbpjpyRsi, gbpusdRsi, usdjpyRsi;
       private BollingerBands gbpjpyBollinger, gbpusdBollinger, usdjpyBollinger;

       private List<string> profitLossLog = new List<string>();

       private double currentHourMaxProfit = double.MinValue;
       private double currentHourMaxLoss = double.MaxValue;

       private DateTime currentHourMaxProfitTime, currentHourMaxLossTime;

       private DateTime startTime;
       private DateTime lastLogTime;
       private DateTime endTime;
       private const int checkPeriodHours = 1;
       private const int totalHours = 24;
       private const int lookbackPeriod = 3;

       private bool gbpjpyOpened = false;
       private bool gbpusdOpened = false;
       private bool usdjpyOpened = false;

       protected override void OnStart()
       {
           gbpjpySymbol = Symbols.GetSymbol("GBPJPY");
           gbpusdSymbol = Symbols.GetSymbol("GBPUSD");
           usdjpySymbol = Symbols.GetSymbol("USDJPY");

           gbpjpyRsi = Indicators.RelativeStrengthIndex(MarketData.GetBars(TimeFrame.Hour, "GBPJPY").ClosePrices, 14);
           gbpusdRsi = Indicators.RelativeStrengthIndex(MarketData.GetBars(TimeFrame.Hour, "GBPUSD").ClosePrices, 14);
           usdjpyRsi = Indicators.RelativeStrengthIndex(MarketData.GetBars(TimeFrame.Hour, "USDJPY").ClosePrices, 14);

           gbpjpyBollinger = Indicators.BollingerBands(MarketData.GetBars(TimeFrame.Hour, "GBPJPY").ClosePrices, 20, 2, MovingAverageType.Simple);
           gbpusdBollinger = Indicators.BollingerBands(MarketData.GetBars(TimeFrame.Hour, "GBPUSD").ClosePrices, 20, 2, MovingAverageType.Simple);
           usdjpyBollinger = Indicators.BollingerBands(MarketData.GetBars(TimeFrame.Hour, "USDJPY").ClosePrices, 20, 2, MovingAverageType.Simple);

           startTime = Server.Time;
           lastLogTime = startTime;
           endTime = startTime.AddHours(totalHours);
       }

       protected override void OnTick()
       {
           int gbpjpySignal = GetRsiBollingerSignal(gbpjpyRsi, gbpjpyBollinger, gbpjpySymbol);
           int gbpusdSignal = GetRsiBollingerSignal(gbpusdRsi, gbpusdBollinger, gbpusdSymbol);
           int usdjpySignal = GetRsiBollingerSignal(usdjpyRsi, usdjpyBollinger, usdjpySymbol);

           HandleOrder(gbpjpySignal, gbpjpySymbol, ref gbpjpyOpened);
           HandleOrder(gbpusdSignal, gbpusdSymbol, ref gbpusdOpened);
           HandleOrder(usdjpySignal, usdjpySymbol, ref usdjpyOpened);

           double currentProfit = 0;
           foreach (var position in Positions)
           {
               currentProfit += position.GrossProfit;
           }

           if (currentProfit > currentHourMaxProfit)
           {
               currentHourMaxProfit = currentProfit;
               currentHourMaxProfitTime = Server.Time;
           }

           if (currentProfit < currentHourMaxLoss)
           {
               currentHourMaxLoss = currentProfit;
               currentHourMaxLossTime = Server.Time;
           }

           if ((Server.Time - lastLogTime).TotalHours >= checkPeriodHours)
           {
               string logEntry = $"Hour {((Server.Time - startTime).TotalHours):F0}: Max Profit: {currentHourMaxProfit}, Time: {currentHourMaxProfitTime}, Max Loss: {currentHourMaxLoss}, Time: {currentHourMaxLossTime}";
               profitLossLog.Add(logEntry);
               Print(logEntry);

               currentHourMaxProfit = double.MinValue;
               currentHourMaxLoss = double.MaxValue;

               lastLogTime = Server.Time;
           }

           if (Server.Time >= endTime)
           {
               Print("24-hour Max Profit and Max Loss:");
               foreach (var entry in profitLossLog)
               {
                   Print(entry);
               }

               Stop();
           }
       }

       private int GetRsiBollingerSignal(RelativeStrengthIndex rsi, BollingerBands bollingerBands, Symbol symbol)
       {
           double rsiValue = rsi.Result.LastValue;
           var bars = MarketData.GetBars(TimeFrame.Hour, symbol.Name);
           if (bars.Count < 2)
               return 0;

           var previousBar = bars[bars.Count - 2];
           double previousBarLow = previousBar.Low;
           double previousBarHigh = previousBar.High;
           double bollingerTop = bollingerBands.Top.LastValue;
           double bollingerBottom = bollingerBands.Bottom.LastValue;
           double previousVolume = bars[bars.Count - 2].Volume;

           bool isDoubleTop = DetectDoubleTop(symbol);
           bool isDoubleBottom = DetectDoubleBottom(symbol);

           if (rsiValue > 70)
           {
               if (previousBarLow > bollingerTop || isDoubleTop)
               {
                   Print($"Overbought condition met: Previous bar low {previousBarLow}, Bollinger Bands top {bollingerTop}, RSI {rsiValue}");
                   if (MarketData.GetBars(TimeFrame.Hour, symbol.Name)[bars.Count - 2].Volume <= previousVolume / 2)
                   {
                       Print("Volume condition met for overbought: Opening short positions");
                       return -1;
                   }
               }
               else
               {
                   return rsiValue > 50 ? 1 : -1;
               }
           }
           else if (rsiValue < 20)
           {
               if (previousBarHigh < bollingerBottom || isDoubleBottom)
               {
                   Print($"Oversold condition met: Previous bar high {previousBarHigh}, Bollinger Bands bottom {bollingerBottom}, RSI {rsiValue}");
                   if (MarketData.GetBars(TimeFrame.Hour, symbol.Name)[bars.Count - 2].Volume <= previousVolume / 2)
                   {
                       Print("Volume condition met for oversold: Opening long positions");
                       return 1;
                   }
               }
               else
               {
                   return rsiValue > 50 ? 1 : -1;
               }
           }
           else
           {
               return rsiValue > 50 ? 1 : -1;
           }

           return 0;
       }

       private bool DetectDoubleTop(Symbol symbol)
       {
           var bars = MarketData.GetBars(TimeFrame.Hour, symbol.Name);
           if (bars.Count < lookbackPeriod * 2)
               return false;

           double peak1 = bars[bars.Count - lookbackPeriod - 1].High;
           double peak2 = bars[bars.Count - 1].High;

           for (int i = 1; i < lookbackPeriod; i++)
           {
               if (Math.Abs(bars[bars.Count - i].High - peak1) < 0.01 && Math.Abs(bars[bars.Count - i].High - peak2) < 0.01)
               {
                   return true;
               }
           }
           return false;
       }

       private bool DetectDoubleBottom(Symbol symbol)
       {
           var bars = MarketData.GetBars(TimeFrame.Hour, symbol.Name);
           if (bars.Count < lookbackPeriod * 2)
               return false;

           double trough1 = bars[bars.Count - lookbackPeriod - 1].Low;
           double trough2 = bars[bars.Count - 1].Low;

           for (int i = 1; i < lookbackPeriod; i++)
           {
               if (Math.Abs(bars[bars.Count - i].Low - trough1) < 0.01 && Math.Abs(bars[bars.Count - i].Low - trough2) < 0.01)
               {
                   return true;
               }
           }
           return false;
       }

       private void HandleOrder(int signal, Symbol symbol, ref bool opened)
       {
           if (signal != 0)
           {
               if (opened)
                   return;

               double volume = (signal > 0) ? 0.02 : 0.01;
               double stopLoss = 50;
               double takeProfit = 50;

               if (signal > 0)
               {
                   Print($"Opening long position: {symbol.Name}");
                   ExecuteMarketOrder(TradeType.Buy, symbol.Name, volume, "RSI Strategy", stopLoss, takeProfit);
               }
               else
               {
                   Print($"Opening short position: {symbol.Name}");
                   ExecuteMarketOrder(TradeType.Sell, symbol.Name, volume, "RSI Strategy", stopLoss, takeProfit);
               }

               opened = true;
           }
           else if (opened)
           {
               foreach (var position in Positions.FindAll("RSI Strategy", symbol.Name))
               {
                   Print($"Closing position: {symbol.Name}");
                   ClosePosition(position);
               }
               opened = false;
           }
       }

       protected override void OnStop()
       {
           // Final logging
           Print("Final 24-hour Max Profit and Max Loss:");
           foreach (var entry in profitLossLog)
           {
               Print(entry);
           }
       }
   }
}


@chenshy27
Replies

PanagiotisCharalampous
19 Sep 2024, 05:48

Hi there,

The problem is that your are calling a property that does not exist. Bars do not have a Volume property.

Best regards,

Panagiotis


@PanagiotisCharalampous