Category Other  Published on 30/05/2024

OFP-Rules

Description

Panel that shows if the account has violated the following rules:
TVR, Daily Drawdown and Maximal Drawdown. 

Please carefully configure the parameters for correct operation.


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

namespace cAlgo
{
  public class DailyPosition
  {
    public DateTime day;
    public double profit;
  }

  [Indicator(AccessRights = AccessRights.None, IsOverlay = true, TimeZone = TimeZones.UTC)]
  public class OFPRules : Indicator
  {
    /*Configuration parameter*/
    [Parameter("Year", DefaultValue = 2023, Group = "Start Date", MinValue = 2000, MaxValue = 2050, Step = 1)]
    public int Year { get; set; }
    [Parameter("Month", DefaultValue = 1, Group = "Start Date", MinValue = 1, MaxValue = 12, Step = 1)]
    public int Month { get; set; }
    [Parameter("Day", DefaultValue = 1, Group = "Start Date", MinValue = 1, MaxValue = 31, Step = 1)]
    public int Day { get; set; }

    [Parameter("Account Size", DefaultValue = 5000, MinValue = 5000, MaxValue = 2500000, Step = 5000, Group = "Balance")]
    public double InitialBalance { get; set; }
    [Parameter("DrawDown Daily(%)", DefaultValue = 5, MinValue = 3, MaxValue = 5, Step = 1, Group = "Balance")]
    public int DrawDownDaily { get; set; }
    [Parameter("DrawDown Maximal(%)", DefaultValue = 10, MinValue = 4, MaxValue = 10, Step = 2, Group = "Balance")]
    public int DrawDownMaximal { get; set; }
    [Parameter("TVR(%)", DefaultValue = 25, MinValue = 12, MaxValue = 25, Step = 1, Group = "Balance")]
    public int TVRPorcent { get; set; }
    /*Color parameter*/
    [Parameter(DefaultValue = "#FFFFFF", Group = "Panel Color")]
    public Color Color { get; set; }
    [Parameter("Transparency", DefaultValue = 0.5, Group = "Panel Color", MinValue = 0.1, MaxValue = 1, Step = 0.1)]
    public double Transparency { get; set; }
    /*Position parameter*/
    [Parameter(name: "Horizontal", DefaultValue = HorizontalAlignment.Left, Group = "Position")]
    public HorizontalAlignment Horizontal { get; set; }
    [Parameter(name: "Vertical", DefaultValue = VerticalAlignment.Bottom, Group = "Position")]
    public VerticalAlignment Vertical { get; set; }

    /*Variables*/
    private DateTime _startDate;
    private int _totalDays;
    private double _totalProfit;
    private double _maxProfitDaily;

    private DateTime _bestDay;
    private double _bestProfit;
    private double _profitPorcent;
    private string _statusTVR;

    private List<DateTime> _tradingDays;
    private double _dailyLoss;//DrawDown Daily Lost 
    private double _ddMinBalance;//Min Balace allowed
    private double _ddViolateBalance;
    private DateTime _ddDate;//DrawDown Daily Date
    private int _ddIDTrade;//ID History Trade
    private string _statusDD;

    private double _maxLoss;//DrawDown Montly Lost
    private double _mdMinBalance;//Min Balance allowed
    private double _mdViolateBalance;
    private DateTime _mdDate;//DrawDown Montly Date
    private int _mdIDTrade;//ID History Trade
    private string _statusMD;
    
    private string _activeTab;

    /*Visual Object*/
    private StackPanel _panel;
    private StackPanel _tabPanel;
    private Grid _grid;
    private Style _textBlocksStyle;
    private Button BtnTVR;
    private Button BtnDD;
    private Button BtnMD;

    protected override void Initialize()
    {
      // To learn more about cTrader Automate visit our Help Center:
      // https://help.ctrader.com/ctrader-automate
      _panel = new StackPanel
      {
        Orientation = Orientation.Vertical,
        HorizontalAlignment = Horizontal,
        VerticalAlignment = Vertical,
        BackgroundColor = Color,
        Opacity = Transparency
      };

      _textBlocksStyle = new Style();
      _textBlocksStyle.Set(ControlProperty.Margin, 2);

      _panel.AddChild(new TextBox
      {
        Text = "OFP rules status",
        FontWeight = FontWeight.ExtraBold,
        HorizontalAlignment = HorizontalAlignment.Stretch,
        TextAlignment = TextAlignment.Center,
        Style = _textBlocksStyle
      });

      _tabPanel = new StackPanel
      {
        Orientation = Orientation.Horizontal,
        HorizontalAlignment = Horizontal,
        VerticalAlignment = Vertical,
        BackgroundColor = Color,
        Opacity = Transparency,
        Width = 170
      };

      //Button TVR
      BtnTVR = new Button
      {
        Text = "TVR",
        FontWeight = FontWeight.Light,
        HorizontalAlignment = HorizontalAlignment.Center,
        Margin = 1,
        Width = 50
      };
      BtnTVR.Click += BtnTVR_Click;
      _tabPanel.AddChild(BtnTVR);

      //Button DD
      BtnDD = new Button
      {
        Text = "DD",
        FontWeight = FontWeight.Light,
        HorizontalAlignment = HorizontalAlignment.Center,
        Margin = 1,
        Width = 50
      };
      BtnDD.Click += BtnDD_Click;
      _tabPanel.AddChild(BtnDD);

      //Button MD
      BtnMD = new Button
      {
        Text = "MD",
        FontWeight = FontWeight.Light,
        HorizontalAlignment = HorizontalAlignment.Center,
        Margin = 1,
        Width = 50
      };
      BtnMD.Click += BtnMD_Click;
      _tabPanel.AddChild(BtnMD);

      _panel.AddChild(_tabPanel);
      Chart.AddControl(_panel);

      RuleTVR();
      RuleDD();
      RuleMD();
      BtnTVR_Click(null);
      Positions.Closed += Positions_Closed;
    }
    public override void Calculate(int index)
    {

    }
    /*---------------------------------------------------------------------------------------------------------*/
    /*--- Events Functions                                                                                     */
    /*---------------------------------------------------------------------------------------------------------*/
    private void Positions_Closed(PositionClosedEventArgs obj)
    {
      RuleTVR();
      RuleDD();
      RuleMD();
      switch (_activeTab)
      {          
          case "DD":
          BtnDD_Click(null);
          break;
          case "MD":
          BtnMD_Click(null);
          break;
          default:
          BtnTVR_Click(null);
          break;
      }
    }

    private void BtnDD_Click(ButtonClickEventArgs obj)
    {
      _activeTab="DD";
      VFClickBtn(BtnDD);

      if (_grid != null)
      {
        _panel.RemoveChild(_grid);
      }
      _grid = new Grid(8, 2);
      //Encabezados del grid
      _grid.AddChild(new TextBlock
      {
        Text = "Status:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 0, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Start Day:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 1, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Daily Lost:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 2, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Min Daily Balance:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 3, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Violation Balance:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 4, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "PositionID:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 5, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Violation Date",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 6, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 7, 0);

      //Datos-----------------------------------
      _grid.AddChild(new TextBlock
      {
        Text = _statusDD,
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 0, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _startDate.ToShortDateString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 1, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _dailyLoss.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 2, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _ddMinBalance.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 3, 1);

      if (_ddDate != DateTime.MinValue)
      {
        _grid.AddChild(new TextBlock
        {
          Text = _ddViolateBalance.ToString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 4, 1);

        _grid.AddChild(new TextBlock
        {
          Text = _ddIDTrade.ToString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 5, 1);

        _grid.AddChild(new TextBlock
        {
          Text = _ddDate.ToShortDateString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 6, 1);
      }

      _panel.AddChild(_grid);
    }

    private void BtnMD_Click(ButtonClickEventArgs obj)
    {
      _activeTab="MD";
      VFClickBtn(BtnMD);
      if (_grid != null)
      {
        _panel.RemoveChild(_grid);
      }
      _grid = new Grid(8, 2);
      //Encabezados del grid
      _grid.AddChild(new TextBlock
      {
        Text = "Status:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 0, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Start Day:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 1, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Max Lost:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 2, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Min Balance:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 3, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Violation Balance:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 4, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "PositionID:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 5, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Violation Date",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 6, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 7, 0);

      //Datos-----------------------------------
      _grid.AddChild(new TextBlock
      {
        Text = _statusMD,
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 0, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _startDate.ToShortDateString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 1, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _maxLoss.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 2, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _mdMinBalance.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 3, 1);

      if (_ddDate != DateTime.MinValue)
      {
        _grid.AddChild(new TextBlock
        {
          Text = _mdViolateBalance.ToString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 4, 1);

        _grid.AddChild(new TextBlock
        {
          Text = _mdIDTrade.ToString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 5, 1);

        _grid.AddChild(new TextBlock
        {
          Text = _mdDate.ToShortDateString(),
          Style = _textBlocksStyle,
          ForegroundColor = Color.Black
        }, 6, 1);
      }

      _panel.AddChild(_grid);
    }

    private void BtnTVR_Click(ButtonClickEventArgs obj)
    {
      _activeTab="TVR";
      VFClickBtn(BtnTVR);
      if (_grid != null)
      {
        _panel.RemoveChild(_grid);
      }
      //Encabezados
      _grid = new Grid(8, 2);

      _grid.AddChild(new TextBlock
      {
        Text = "Status:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 0, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Start Day:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 1, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Total trading days:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 2, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Total Profit:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 3, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Max profit allowed:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 4, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Best Day:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 5, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Best Profit:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 6, 0);

      _grid.AddChild(new TextBlock
      {
        Text = "Profit %:",
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black,
        FontWeight = FontWeight.Bold
      }, 7, 0);

      //Datos-----------------------------------
      _grid.AddChild(new TextBlock
      {
        Text = _statusTVR,
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 0, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _startDate.ToShortDateString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 1, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _totalDays.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 2, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _totalProfit.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 3, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _maxProfitDaily.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 4, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _bestDay.ToShortDateString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 5, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _bestProfit.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 6, 1);

      _grid.AddChild(new TextBlock
      {
        Text = _profitPorcent.ToString(),
        Style = _textBlocksStyle,
        ForegroundColor = Color.Black
      }, 7, 1);

      _panel.AddChild(_grid);
    }
    /*---------------------------------------------------------------------------------------------------------*/
    /*--- Visual Functions                                                                                      */
    /*---------------------------------------------------------------------------------------------------------*/
    private void VFClickBtn(Button btn)
    {
      BtnDD.FontWeight = FontWeight.Light;
      BtnMD.FontWeight = FontWeight.Light;
      BtnTVR.FontWeight = FontWeight.Light;

      BtnDD.ForegroundColor = Color.White;
      BtnMD.ForegroundColor = Color.White;
      BtnTVR.ForegroundColor = Color.White;

      BtnDD.FontSize = 10;
      BtnMD.FontSize = 10;
      BtnTVR.FontSize = 10;

      btn.FontWeight = FontWeight.ExtraBold;
      btn.ForegroundColor = Color.Black;
      btn.FontSize = 12;
    }
    /*---------------------------------------------------------------------------------------------------------*/
    /*--- Rules Functions                                                                                      */
    /*---------------------------------------------------------------------------------------------------------*/
    private void RuleTVR()
    {
      try
      {
        _startDate = new DateTime(Year, Month, Day);
      }
      catch (Exception)
      {
        _startDate = new DateTime();
        Print("Year:", Year, " Month:", Month, " Day:", Day, " It is not valid Date.");
      }

      _totalProfit = Math.Round(History.Where(h => h.ClosingTime >= _startDate).Sum(h => h.NetProfit), 2);
      _maxProfitDaily = Math.Round(_totalProfit * TVRPorcent / 100, 2);

      //Obteniendo el listado de dias de posiciones cerradas del historial
      _tradingDays = History.Where(h => h.ClosingTime >= _startDate).Select(h => new DateTime(h.ClosingTime.Year, h.ClosingTime.Month, h.ClosingTime.Day)).Distinct().OrderBy(h => h).ToList();
      _totalDays = _tradingDays.Count;

      var tmpPositionsList = new List<DailyPosition>();
      //Calculando el profit por dia
      foreach (var iday in _tradingDays)
      {
        var tmpDailyProfit = History.Where(h => h.ClosingTime.Year == iday.Year && h.ClosingTime.Month == iday.Month && h.ClosingTime.Day == iday.Day).Sum(p => p.NetProfit);
        var tmpDP = new DailyPosition()
        {
          day = iday,
          profit = tmpDailyProfit
        };
        tmpPositionsList.Add(tmpDP);
      }

      //Buscando el mejor dia por profit
      var bestDP = tmpPositionsList.OrderByDescending(p => p.profit).FirstOrDefault();
      if (bestDP != null)
      {
        _bestDay = bestDP.day;
        _bestProfit =Math.Round( bestDP.profit,2);
        if (_totalProfit == 0)
        {
          _profitPorcent = 0;
        }
        else
        {
          _profitPorcent = Math.Round((_bestProfit * 100) / _totalProfit, 2);
        }
      }
      if (_profitPorcent > 0 && _profitPorcent < TVRPorcent) { _statusTVR = "OK"; }
      else { _statusTVR = "FAILED!!!"; }
    }

    private void RuleDD()
    {
      _dailyLoss = Math.Round((InitialBalance * DrawDownDaily) / 100, 2);
      _ddDate = DateTime.MinValue;
      double dailyBalance = 0;
      double minBalance = 0;
      //Obteniendo el Balance Inicial
      var ftrade = History.FirstOrDefault(t => t.ClosingTime >= _startDate);
      if (ftrade != null)
      {
        dailyBalance = ftrade.Balance - ftrade.NetProfit;
      }
      else
      {
        dailyBalance = Account.Balance;
      }
      minBalance = dailyBalance - _dailyLoss;

      bool violated = false;
      foreach (var iday in _tradingDays)
      {
        var tmpTradesDaysList = History.Where(t => t.ClosingTime.Year == iday.Year &&
                                            t.ClosingTime.Month == iday.Month &&
                                            t.ClosingTime.Day == iday.Day).ToList();
        var tmptrade = tmpTradesDaysList.FirstOrDefault();
        if (tmptrade != null)
        {
          dailyBalance = tmptrade.Balance - tmptrade.NetProfit;
        }
        Print("DailyB: ", dailyBalance);
        foreach (var itrade in tmpTradesDaysList)
        {
          //dailyBalance=itrade.Balance;
          if (itrade.Balance > dailyBalance)
          {
            dailyBalance = itrade.Balance;
            minBalance = dailyBalance - _dailyLoss;
          }
          if (itrade.Balance < minBalance)
          {
            _ddViolateBalance = itrade.Balance;
            _ddIDTrade = itrade.PositionId;
            _ddDate = itrade.ClosingTime;
            violated = true;
            break;
          }
        }
        if (violated)
        {
          break;
        }
      }
      if (violated)
      {
        _statusDD = "VIOLATED!!!";
        _ddMinBalance = dailyBalance - _dailyLoss;
      }
      else
      {
        _statusDD = "OK";
        var tmplastrade = History.LastOrDefault();
        if (tmplastrade != null && tmplastrade.ClosingTime.DayOfYear == DateTime.Now.DayOfYear)
        {
          _ddMinBalance = dailyBalance - _dailyLoss;
        }
        else
        {
          _ddMinBalance = Account.Balance - _dailyLoss;
        }
      }
        _ddMinBalance=Math.Round(_ddMinBalance,2);
    }

    private void RuleMD()
    {
      _maxLoss = Math.Round((InitialBalance * DrawDownMaximal) / 100, 2);
      _mdDate = DateTime.MinValue;
      double maxBalance = 0;
      double minBalance = 0;
      //Obteniendo el Balance Inicial
      var ftrade = History.FirstOrDefault(t => t.ClosingTime >= _startDate);
      if (ftrade != null)
      {
        maxBalance = ftrade.Balance - ftrade.NetProfit;
      }
      else
      {
        maxBalance = Account.Balance;
      }
      minBalance = maxBalance - _maxLoss;
      bool violated = false;

      var tmpTradesDaysList = History.Where(t => t.ClosingTime >= _startDate).ToList();

      foreach (var itrade in tmpTradesDaysList)
      {
        maxBalance = itrade.Balance;
        if (itrade.Balance > maxBalance)
        {
          maxBalance = itrade.Balance;
          minBalance = maxBalance - _maxLoss;
        }
        if (itrade.Balance < minBalance)
        {
          _mdViolateBalance = itrade.Balance;
          _mdIDTrade = itrade.PositionId;
          _mdDate = itrade.ClosingTime;
          violated = true;
          break;
        }
      }

      if (violated)
      {
        _statusMD = "VIOLATED!!!";
      }
      else
      {
        _statusMD = "OK";
      }
      
      _mdMinBalance =Math.Round(minBalance,2);
    }
  }
}

AN
Angell

Joined on 29.05.2024

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: OFP-Rules.algo
  • Rating: 5
  • Installs: 312
  • Modified: 30/05/2024 08:50
Comments
Log in to add a comment.
JD
jdgl0021 · 3 months ago

Disculpa porque no tiene nada que ver con este tema. Pero soy cliente de OFP, y al migrar las cuentas a CTRADER no se pueden operar los indices porque tienen 20 puntos de spread, y me han dicho por dos veces que esos son los spreads actuales. Vamos no se si a ti o a otros os pasa lo mismo. Esto es de verguenza