Description
An Indicator that shows the long and short average entries on the chart. Swaps are included in the calculations.
This indicator is experimental and still in development and may contains bugs!
Parameters:
- Show Text - Shows or Hides the text under the break-even lines on chart
using cAlgo.API;
using System;
using System.Collections.Generic;
using System.Linq;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AverageEntry : Indicator
{
private readonly string TAG = Guid.NewGuid().ToString() + "-AVG";
#region Parameters
[Parameter("Show Text ?", DefaultValue = true)]
public bool ShowText { get; set; }
#endregion Parameters
#region Helper Functions
/// <summary>
/// Get all opened positions for current Symbol
/// </summary>
public Position[] GetSymbolOpenPositions()
=> Positions
.Where(position => position.SymbolName == Symbol.Name)
.ToArray();
/// <summary>
/// Get all opened positions for current Symbol with Trade Type (Buy / Sell)
/// </summary>
public Position[] GetSymbolOpenPositions(TradeType tradeType)
=> Positions
.Where(position => position.SymbolName == Symbol.Name && position.TradeType == tradeType)
.ToArray();
/// <summary>
/// Get the Total Volume of Opened Positions
/// </summary>
public double GetOpenPositionsVolume()
=> GetSymbolOpenPositions().Select(p => p.VolumeInUnits).Sum();
/// <summary>
/// Get the Total Volume of Opened Positions with Trade Type (Buy / Sell)
/// </summary>
public double GetOpenPositionsVolume(TradeType tradeType)
=> GetSymbolOpenPositions(tradeType).Select(p => p.VolumeInUnits).Sum();
/// <summary>
/// Returns the Net Volume Exposure in Units
/// </summary>
public double NetVolumeExposure
=> GetOpenPositionsVolume(TradeType.Buy) - GetOpenPositionsVolume(TradeType.Sell);
#endregion
#region Calculate Break-Even
// Calculate Break-Even Price for Longs or Shorts
protected void CalculateBreakEven(TradeType tradeType, int index)
{
// Skip if no Open Positions
if (GetSymbolOpenPositions(tradeType).Length == 0)
return;
double swap = 0.0;
double entryVol = 0;
foreach (Position position in Positions)
{
if (position.SymbolName != Symbol.Name || position.TradeType != tradeType)
continue;
int _direction = position.TradeType == TradeType.Sell ? -1 : 1;
double vol = position.VolumeInUnits * _direction;
entryVol += position.EntryPrice * vol;
swap += position.Swap;
}
double breakEvenPrice1 = Math.Abs(entryVol / GetOpenPositionsVolume(tradeType));
CalculateBE(tradeType, breakEvenPrice1, swap, index);
}
private void CalculateBE(TradeType? tradeType, double breakEvenPrice1, double swap, int index)
{
/* Full Formula:
* C * (P₂ - P₁) = |S|
* Where:
* -- C = (Volume * Pip Value) / Pip size
* -- P₁ = Average Entry Before Swaps
* -- P₂ = Break-Even Price
* -- |S| = Absolute Swap Value
*/
double volume = tradeType == null ? NetVolumeExposure : GetOpenPositionsVolume((TradeType)tradeType);
double constant = (volume * Symbol.PipValue) / Symbol.PipSize;
double breakEvenPrice2 = Math.Abs(swap / constant) * (tradeType == null ? -1 : 1) + breakEvenPrice1;
int multipler = ((tradeType == TradeType.Buy && breakEvenPrice2 > Bars.LastBar.Close) || (tradeType == TradeType.Sell && breakEvenPrice2 < Bars.LastBar.Close)) ? -1 : 1;
double distance = multipler * (Math.Abs(breakEvenPrice2 - Bars.LastBar.Close) / Symbol.PipSize);
string lineID = "breakEvenPrice";
Color objCol = Color.Yellow;
string direction = "AVG";
if (tradeType != null)
{
direction = "AVG " + ((tradeType == TradeType.Buy) ? "L" : "S");
objCol = (tradeType == TradeType.Buy) ? Color.Green : Color.Red;
lineID += direction;
}
string text = string.Format("{0}: [{1:0.00000} | {2:0.00} Pips]", direction, breakEvenPrice2, distance);
string textID = lineID + "Text";
string avgLineName = TAG + lineID;
Chart.DrawTrendLine(avgLineName, index - 3, breakEvenPrice2, index + 10, breakEvenPrice2, objCol);
if (!ShowText)
return;
string textName = TAG + textID;
Chart.DrawText(textName, text, index - 2, breakEvenPrice2, objCol);
}
private void DrawAverageEntry()
{
int index = Bars.ClosePrices.Count - 1;
bool longsExist = GetSymbolOpenPositions(TradeType.Buy).Length > 0;
bool shortsExist = GetSymbolOpenPositions(TradeType.Sell).Length > 0;
if (longsExist)
CalculateBreakEven(TradeType.Buy, index);
if (shortsExist)
CalculateBreakEven(TradeType.Sell, index);
}
#endregion
public override void Calculate(int index) {}
protected override void Initialize()
{
CallEvents();
Timer.Start(1);
}
#region Events
/// <summary>
/// Update Average Positions on all Events
/// </summary>
public void CallEvents()
{
Positions.Opened += OnPositionsOpened;
Positions.Closed += OnPositionsClosed;
Positions.Modified += OnPositionsModified;
Chart.ScrollChanged += OnChartScrollChanged;
Chart.SizeChanged += OnChartSizeChanged;
Chart.ZoomChanged += OnChartZoomChanged;
}
public void RemoveObjects()
=> Chart.Objects
.Where(o => o.Name.StartsWith(TAG))
.ToList()
.ForEach(obj => Chart.RemoveObject(obj.Name));
protected override void OnTimer()
=> DrawAverageEntry();
private void OnChartScrollChanged(ChartScrollEventArgs _)
=> RemoveObjects();
private void OnChartSizeChanged(ChartSizeEventArgs _)
=> RemoveObjects();
private void OnChartZoomChanged(ChartZoomEventArgs _)
=> RemoveObjects();
private void OnPositionsClosed(PositionClosedEventArgs _)
=> RemoveObjects();
private void OnPositionsModified(PositionModifiedEventArgs _)
=> RemoveObjects();
private void OnPositionsOpened(PositionOpenedEventArgs _)
=> RemoveObjects();
#endregion Events
}
}
Botnet101
Joined on 08.08.2021
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Average Entry.algo
- Rating: 5
- Installs: 1204
- Modified: 04/07/2022 23: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.
RO
Great Idea Botnet101. If you can add a Change of Colour and position (right, middle, left) on the chart. Great job.
Thanks Botnet101, that's a really useful indicator!
Another suggestion would be to show the point of breakeven positions of both long and short entries (although it's more complicated and would need to take into account long and short position sizes).