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: 409
- Modified: 30/05/2024 08:50
Note that publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section, please use the Copyright Infringement Notification form to submit a claim.
Comments
Log in to add a comment.
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